/*=============================================================================
D3DFXPipeline.cpp : Direct3D specific FX shaders rendering pipeline.
Copyright (c) 2001 Crytek Studios. All Rights Reserved.

Revision history:
* Created by Honich Andrey

=============================================================================*/

#include "StdAfx.h"
#include "DriverD3D.h"
#include "D3DLightPropagationVolume.h"
#include <I3DEngine.h>
#include <IEntityRenderState.h>
#include "../Common/PostProcess/PostEffects.h"
#include "DXPS/SkinVT.h"
#include "RenderObjectDefines.h"

//====================================================================================

// #pragma warning(disable: 6326)

#if defined (DIRECT3D9)
namespace D3D9R2VBHelper
{
	enum eR2VBConstants
	{
		R2VB_GLB_ENA_CMD = 0x0,
		R2VB_VS2SM_CMD = 0x1,
		// R2VB Command Token
		R2VB_TOK_CMD_SHFT = 24,
		R2VB_TOK_CMD_MSK = 0x0F000000,
		R2VB_TOK_CMD_MAG = 0x70FF0000,
		R2VB_TOK_CMD_MAT = 0xFFFF0000,
		R2VB_TOK_PLD_MSK = 0x0000FFFF,
		R2VB_GLB_ENA_MSK = 0x1,
		R2VB_VS2SM_STRM_MSK = 0xF,
		R2VB_VS2SM_SMP_SHFT = 0x4,
		R2VB_VS2SM_SMP_MSK = 0x7,
		// R2VB enums
		R2VB_VSMP_OVR_DMAP = 0, // override stream with dmap sampler
		R2VB_VSMP_OVR_VTX0 = 1, // override stream with vertex texture 0 sampler
		R2VB_VSMP_OVR_VTX1 = 2, // override stream with vertex texture 1 sampler
		R2VB_VSMP_OVR_VTX2 = 3, // override stream with vertex texture 2 sampler
		R2VB_VSMP_OVR_VTX3 = 4, // override stream with vertex texture 3 sampler
		R2VB_VSMP_OVR_DIS = 5, // disable stream override
		R2VB_VSMP_OVR_NUM = 6, //
		R2VB_VSMP_NUM = 5, // 5 available texture samplers
	};

	DWORD r2vbToken_Set(DWORD cmd, DWORD payload)
	{
		DWORD cmd_token = (cmd << R2VB_TOK_CMD_SHFT) & R2VB_TOK_CMD_MSK;
		DWORD pld_data = payload & R2VB_TOK_PLD_MSK;
		return (R2VB_TOK_CMD_MAG | cmd_token | pld_data);
	}
	DWORD r2vbGlbEnable_Set(BOOL ena)
	{
		DWORD payload = ena & R2VB_GLB_ENA_MSK;
		DWORD dw = r2vbToken_Set(R2VB_GLB_ENA_CMD, payload);
		return dw;
	}
	DWORD r2vbVStrm2SmpMap_Set(DWORD str, DWORD smp)
	{
		DWORD sampler = (smp & R2VB_VS2SM_SMP_MSK) << R2VB_VS2SM_SMP_SHFT;
		DWORD stream = (str & R2VB_VS2SM_STRM_MSK);
		DWORD payload = sampler | stream;
		DWORD dw = r2vbToken_Set(R2VB_VS2SM_CMD, payload);
		return dw;
	}
}
#endif 

HRESULT CD3D9Renderer::FX_SetTextureAsVStream( int nID, CTexture *pVBTexture, uint32 nStride )
{
	if(!(m_Features & RFT_HW_R2VB) || (pVBTexture && (!(pVBTexture->GetFlags() & FT_USAGE_VERTEX_BUFFER) || pVBTexture->GetDevTexture() == NULL))	|| nID > 3)
	{
		assert(0);
		return E_FAIL;
	}

	const BOOL bSetVB = pVBTexture != NULL;
















#if defined (DIRECT3D9)
	// Enable render to vertex buffer extension
	HRESULT hr = m_pd3dDevice->SetRenderState(D3DRS_POINTSIZE, D3D9R2VBHelper::r2vbGlbEnable_Set(bSetVB));
	assert(SUCCEEDED(hr));
	if(bSetVB)
	{
		// Setup stream nID R2VB data
		hr = m_pd3dDevice->SetTexture(D3DVERTEXTEXTURESAMPLER0 + nID, pVBTexture->GetDevTexture()->Get2DTexture());
		assert(SUCCEEDED(hr));
		// Tell the driver that stream nID is to be fetched from the DMAP texture
		hr = m_pd3dDevice->SetRenderState(D3DRS_POINTSIZE, D3D9R2VBHelper::r2vbVStrm2SmpMap_Set(nID, D3D9R2VBHelper::R2VB_VSMP_OVR_VTX0 + nID));
		assert(SUCCEEDED(hr));
	}
	else
	{
		hr = m_pd3dDevice->SetTexture(D3DVERTEXTEXTURESAMPLER0 + nID, NULL);
		assert(SUCCEEDED(hr));
		// Stream 1 restored to regular vertex buffer mode
		hr = m_pd3dDevice->SetRenderState(D3DRS_POINTSIZE, D3D9R2VBHelper::r2vbVStrm2SmpMap_Set(1, D3D9R2VBHelper::R2VB_VSMP_OVR_DIS));
		assert(SUCCEEDED(hr));
	}
#elif defined (DIRECT3D10)
	// the feature is not supported
#endif

	return S_OK;
}

///////////////////////////////////////////

HRESULT CD3D9Renderer::FX_SetVertexDeclaration(int StreamMask, EVertexFormat eVF)
{
	FUNCTION_PROFILER_RENDER_FLAT
  HRESULT hr;

  assert (eVF>=0 && eVF<eVF_Max);

	bool bMorph = (StreamMask&VSM_MORPHBUDDY)!=0;

	SOnDemandD3DVertexDeclarationCache *pDeclCache = &m_RP.m_D3DVertexDeclarationCache[(StreamMask&0xff)>>1][eVF][bMorph?1:0];
	if (!pDeclCache->m_pDeclaration)
  {
		SOnDemandD3DVertexDeclaration Decl;

		EF_OnDemandVertexDeclaration(Decl, (StreamMask&0xff)>>1, eVF, bMorph);
    if (!Decl.m_Declaration.size())
      return S_FALSE;

#if defined (DIRECT3D9)
    if(FAILED(hr = m_pd3dDevice->CreateVertexDeclaration(&Decl.m_Declaration[0], &pDeclCache->m_pDeclaration)))
      return hr;
#elif defined (DIRECT3D10)
    if(!CHWShader_D3D::m_pCurInstVS || !CHWShader_D3D::m_pCurInstVS->m_pShaderData || CHWShader_D3D::m_pCurInstVS->m_bFallback)
      return -1;
    assert(CHWShader_D3D::m_pCurInstVS->m_pShaderData);
    int nSize = CHWShader_D3D::m_pCurInstVS->m_nDataSize;
    void *pVSData = CHWShader_D3D::m_pCurInstVS->m_pShaderData;
    if (FAILED(hr = m_pd3dDevice->CreateInputLayout(&Decl.m_Declaration[0], Decl.m_Declaration.Num(), pVSData, nSize, &pDeclCache->m_pDeclaration)))
    {
      return hr;
    }
#endif
  }
  D3DVertexDeclaration *pD3DDecl = pDeclCache->m_pDeclaration;
#if defined (DIRECT3D9) && !defined (XENON)
  if (CV_d3d9_debugruntime)
#endif
  // Don't render fallback on XENON
  if (!CHWShader_D3D::m_pCurInstVS || !CHWShader_D3D::m_pCurInstPS || (CHWShader_D3D::m_pCurInstVS->m_bFallback | CHWShader_D3D::m_pCurInstPS->m_bFallback))
	{
		FX_Commit();
    return -1;
	}




  if (m_pLastVDeclaration != pD3DDecl)
  {
#if defined (DIRECT3D9)
    m_pLastVDeclaration = pD3DDecl;
    return m_pd3dDevice->SetVertexDeclaration(pD3DDecl);
#elif defined (DIRECT3D10) 
    // Don't set input layout on fallback shader (crashes in DX11 NV driver)
    if (!CHWShader_D3D::m_pCurInstVS || CHWShader_D3D::m_pCurInstVS->m_bFallback)
       return -1;
    m_pLastVDeclaration = pD3DDecl;
    m_pd3dDeviceContext->IASetInputLayout(pD3DDecl);
#endif
  }
#if defined (DIRECT3D10)
  // Don't render fallback in DX11
  if (!CHWShader_D3D::m_pCurInstVS || !CHWShader_D3D::m_pCurInstPS || CHWShader_D3D::m_pCurInstVS->m_bFallback || CHWShader_D3D::m_pCurInstPS->m_bFallback)
    return -1;
#endif
  return S_OK;
}

// Clear buffers (color, depth/stencil)
void CD3D9Renderer::EF_ClearBuffers(uint32 nFlags, const ColorF *Colors, float fDepth, uint8 nStencil)
{
  if (nFlags & FRT_CLEAR_FOGCOLOR)
	{
		for(int i=0;i<RT_STACK_WIDTH;++i)
			m_pNewTarget[i]->m_ReqColor = m_cClearColor;
	}
  else
  if (nFlags & FRT_CLEAR_COLOR)
  {
    if (Colors)
		{
			for(int i=0;i<RT_STACK_WIDTH;++i)
				m_pNewTarget[i]->m_ReqColor = *Colors;
		}
    else
    if(m_wireframe_mode>R_SOLID_MODE)
		{
			for(int i=0;i<RT_STACK_WIDTH;++i)
				m_pNewTarget[i]->m_ReqColor = ColorF(0.25f,0.5f,1.0f,0);
		}
    else
		{
			for(int i=0;i<RT_STACK_WIDTH;++i)
				m_pNewTarget[i]->m_ReqColor = m_cClearColor;
		}
  }

  if (nFlags & FRT_CLEAR_DEPTH)
    m_pNewTarget[0]->m_fReqDepth = fDepth;

	if (!(nFlags & FRT_CLEAR_IMMEDIATE))
    m_pNewTarget[0]->m_ClearFlags = 0;
  if (nFlags & FRT_CLEAR_DEPTH)
    m_pNewTarget[0]->m_ClearFlags |= D3DCLEAR_ZBUFFER;
  if (nFlags & FRT_CLEAR_COLOR)
		m_pNewTarget[0]->m_ClearFlags |= D3DCLEAR_TARGET;
	if (nFlags & FRT_CLEAR_COLORMASK)
		m_pNewTarget[0]->m_ClearFlags |= FRT_CLEAR_COLORMASK;
	if (nFlags & FRT_CLEAR_RESET_VIEWPORT)
		m_pNewTarget[0]->m_bResetViewportForClear = true;

  if (m_sbpp && (nFlags & FRT_CLEAR_STENCIL))
	{
    m_pNewTarget[0]->m_ClearFlags |= D3DCLEAR_STENCIL;
		m_pNewTarget[0]->m_nReqStencil = nStencil;
	}

	if (nFlags & FRT_CLEAR_IMMEDIATE)
		FX_SetActiveRenderTargets(true);
}

void CD3D9Renderer::FX_ClearRegion(const uint32 nAdditionalStates/* = 0*/)
{
  assert(m_pRT->IsRenderThread());

  CRenderObject *pObj = m_RP.m_pCurObject;
  CShader *pSHSave = m_RP.m_pShader;
  SShaderTechnique *pSHT = m_RP.m_pCurTechnique;
  SShaderPass *pPass = m_RP.m_pCurPass;
  SRenderShaderResources *pShRes = m_RP.m_pShaderResources;

	gRenDev->m_cEF.mfRefreshSystemShader("Common", CShaderMan::m_ShaderCommon);

	FX_SetMSAAFlagsRT();

  m_RP.m_PersFlags1 |= RBPF1_IN_CLEAR;
  CShader *pSH = CShaderMan::m_ShaderCommon;
  uint32 nPasses = 0;
  pSH->FXSetTechnique("Clear");
  pSH->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
  pSH->FXBeginPass(0);
  int nState = GS_NODEPTHTEST;
  if (m_pNewTarget[0]->m_ClearFlags & (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL))
  {
    nState = GS_DEPTHFUNC_GREAT;
    nState &= ~GS_NODEPTHTEST;
    nState |= GS_DEPTHWRITE;
  }
	nState |= nAdditionalStates;

  FX_SetState(nState, -1);
  D3DSetCull(eCULL_None);
  float fX = (float)m_CurViewport.nWidth;
  float fY = (float)m_CurViewport.nHeight;
  DrawQuad(-0.5f, -0.5f, fX-0.5f, fY-0.5f, m_pNewTarget[0]->m_ReqColor, 1.0f, fX, fY, fX, fY);
  m_RP.m_PersFlags1 &= ~RBPF1_IN_CLEAR;

  m_RP.m_pCurObject = pObj;
  m_RP.m_pShader = pSHSave;
  m_RP.m_pCurTechnique = pSHT;
  m_RP.m_pCurPass = pPass;
	m_RP.m_pShaderResources = pShRes;
}

void CD3D9Renderer::FX_SetActiveRenderTargets(bool bAllowDIP)
{
  if (m_RP.m_PersFlags1 & RBPF1_IN_CLEAR)
    return;
	FUNCTION_PROFILER_RENDER_FLAT
  HRESULT hr = S_OK;
  bool bDirty = false;
  if (m_nMaxRT2Commit >= 0)
  {
    for (int i=0; i<=m_nMaxRT2Commit; i++)
    {
      if (!m_pNewTarget[i]->m_bWasSetRT)
      {
        m_pNewTarget[i]->m_bWasSetRT = true;
        if (m_pNewTarget[i]->m_pTex)
          m_pNewTarget[i]->m_pTex->SetResolved(false);
        m_pCurTarget[i] = m_pNewTarget[i]->m_pTex;
        bDirty = true;
#ifndef _RELEASE
        if (m_LogFile)
        {
          Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], " +++ Set RT");
          if (m_pNewTarget[i]->m_pTex)
          {
            Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], " '%s'", m_pNewTarget[i]->m_pTex->GetName());
            Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], " Format:%s", CTexture::NameForTextureFormat( m_pNewTarget[i]->m_pTex->m_eTFDst));
            Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], " Type:%s", CTexture::NameForTextureType( m_pNewTarget[i]->m_pTex->m_eTT));
            Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], " W/H:%d:%d\n",  m_pNewTarget[i]->m_pTex->GetWidth(), m_pNewTarget[i]->m_pTex->GetHeight());

          }
          else
          {
            Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], " 'Unknown'\n");
          }
        }
#endif
        CTexture *pRT = m_pNewTarget[i]->m_pTex;
        if (pRT && pRT->UseMultisampledRTV())
          pRT->Unbind();

#if defined (DIRECT3D9)
				{
					PROFILE_FRAME(SetRenderTarget);
					hr = m_pd3dDevice->SetRenderTarget(i, m_pNewTarget[i]->m_pTarget);
				}
#ifndef _RELEASE
        m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumRTChanges++;
#endif
        if (CV_r_stats == 11)
          EF_AddRTStat(pRT);
        if (pRT && pRT->m_pRenderTargetData)
        {
          if (pRT->m_pRenderTargetData->m_nRTSetFrameID != m_RP.m_TI[m_RP.m_nProcessThreadID].m_nFrameUpdateID)
          {
            pRT->m_pRenderTargetData->m_nRTSetFrameID = m_RP.m_TI[m_RP.m_nProcessThreadID].m_nFrameUpdateID;
#ifndef _RELEASE
            m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumRTs++;
#endif
            m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTSize += pRT->GetDeviceDataSize();
            if (CV_r_stats == 12)
              EF_AddRTStat(pRT);
          }
        }
#endif
      }
    }
    if (!m_pNewTarget[0]->m_bWasSetD)
    {
      m_pNewTarget[0]->m_bWasSetD = true;
      bDirty = true;
#if defined (DIRECT3D9)
			{
				PROFILE_FRAME(SetDepthStencilSurface);
				hr = m_pd3dDevice->SetDepthStencilSurface(m_pNewTarget[0]->m_pDepth);
			}














#endif
    }
    //m_nMaxRT2Commit = -1;
  }
#if defined (DIRECT3D10)
  if (bDirty)
  {
    #if !defined (PS3) // For PS3 we allow textures currently being used as RenderTargets
      if (m_pNewTarget[0]->m_pTex && m_pNewTarget[0]->m_pTex->UseMultisampledRTV()) 
      {
        // Reset all texture slots which are used as RT currently
        ID3D11ShaderResourceView *pRes = NULL;
        for (int i=0; i<MAX_TMU; i++)
        {
          if (CTexture::s_TexStages[i].m_Texture == m_pNewTarget[0]->m_pTex)
          {
            m_pd3dDeviceContext->PSSetShaderResources(i, 1, &pRes);
            CTexture::s_TexStages[i].m_Texture = NULL;
          }
        }
      }
    #endif
    
    //m_pd3dDeviceContext->OMSetRenderTargets(m_pNewTarget[0]->m_pTarget==NULL?0:1, &m_pNewTarget[0]->m_pTarget, m_pNewTarget[0]->m_pDepth);
    ID3D11RenderTargetView *pRTV[RT_STACK_WIDTH] = {NULL,NULL,NULL,NULL}; 

    const uint32 nNumViews = max(m_nMaxRT2Commit+1, 0);
    for (uint32 r=0; r<nNumViews; ++r)
    {        
      if (m_pNewTarget[r])
        pRTV[r] = (ID3D11RenderTargetView *)m_pNewTarget[r]->m_pTarget;
    }

    m_pd3dDeviceContext->OMSetRenderTargets(m_pNewTarget[0]->m_pTarget==NULL?0:nNumViews, pRTV, m_pNewTarget[0]->m_pDepth);


    
    /*D3D11_RENDER_TARGET_VIEW_DESC RTV;
    if (m_pNewTarget[0]->m_pTarget)
    {
      m_pNewTarget[0]->m_pTarget->GetDesc(&RTV);
      if (m_pNewTarget[0]->m_pTex)
      {
        D3DTexture *pT = (D3DTexture *)m_pNewTarget[0]->m_pTex->m_pDevTexture;
        if (pT)
        {
          D3D11_RESOURCE_DIMENSION Type;
          pT->GetType(&Type);
          D3D11_TEXTURE2D_DESC TX;
          pT->GetDesc(&TX);
        }
      }
    }*/
  }
#endif

  if( m_nMaxRT2Commit >= 0)
    m_nMaxRT2Commit = -1;

  // Set current viewport
  if (m_bViewportDirty)
  {
    m_bViewportDirty = false;
    if (m_CurViewport != m_NewViewport)
    {
      m_CurViewport = m_NewViewport;
      D3DViewPort Port;
#if defined (DIRECT3D9)
			Port.Width = m_CurViewport.nWidth;
			Port.Height = m_CurViewport.nHeight;
      Port.X = m_CurViewport.nX;
      Port.Y = m_CurViewport.nY;
#if defined(INVERT_DEPTH_RANGE)
      Port.MinZ = m_CurViewport.fMaxZ;
      Port.MaxZ = m_CurViewport.fMinZ;
#else
      Port.MinZ = m_CurViewport.fMinZ;
      Port.MaxZ = m_CurViewport.fMaxZ;
#endif
      hr = m_pd3dDevice->SetViewport(&Port);
#elif defined (DIRECT3D10)






			Port.Width = (FLOAT)m_CurViewport.nWidth;
			Port.Height = (FLOAT)m_CurViewport.nHeight;
      Port.TopLeftX = (FLOAT)m_CurViewport.nX;
      Port.TopLeftY = (FLOAT)m_CurViewport.nY;

      Port.MinDepth = m_CurViewport.fMinZ;
      Port.MaxDepth = m_CurViewport.fMaxZ;
      m_pd3dDeviceContext->RSSetViewports(1, &Port);
#endif
    }
  }












  if (m_pNewTarget[0]->m_ClearFlags)
  {
    //m_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
    DWORD cColor = D3DRGBA(m_pNewTarget[0]->m_ReqColor[0], m_pNewTarget[0]->m_ReqColor[1], m_pNewTarget[0]->m_ReqColor[2], m_pNewTarget[0]->m_ReqColor[3]);
#if defined (DIRECT3D9)








		// AntonK: need to remove these checks after we have fixed issues with recursive rendering
		if(m_pNewTarget[0]->m_pTarget == NULL)
		{
			assert((m_pNewTarget[0]->m_ClearFlags & FRT_CLEAR_COLOR) == 0);
			m_pNewTarget[0]->m_ClearFlags &= ~FRT_CLEAR_COLOR;
		}

		D3DVIEWPORT9 oldVp;
		
		if(m_pNewTarget[0]->m_bResetViewportForClear)
		{
			m_pd3dDevice->GetViewport(&oldVp);

			D3DVIEWPORT9 vp;
			vp.X      = 0;
			vp.Y      = 0;
			vp.Width  = m_pNewTarget[0]->m_Width;
			vp.Height = m_pNewTarget[0]->m_Height;
			vp.MinZ   = 0.0f;
			vp.MaxZ   = 1.0f;

			m_pd3dDevice->SetViewport(&vp);
		}

#if defined(INVERT_DEPTH_RANGE)
    hr = m_pd3dDevice->Clear(0, NULL, m_pNewTarget[0]->m_ClearFlags, cColor, 1.0f-m_pNewTarget[0]->m_fReqDepth, m_pNewTarget[0]->m_nReqStencil);
    assert(SUCCEEDED(hr));
#else
    hr = m_pd3dDevice->Clear(0, NULL, m_pNewTarget[0]->m_ClearFlags, cColor, m_pNewTarget[0]->m_fReqDepth, m_pNewTarget[0]->m_nReqStencil);
    assert(SUCCEEDED(hr));
#endif

		if(m_pNewTarget[0]->m_bResetViewportForClear)
		{
			m_pd3dDevice->SetViewport(&oldVp);
			m_pNewTarget[0]->m_bResetViewportForClear = false;
		}








#elif defined (DIRECT3D10)
    bool bEntireClear = true;
     
    if  (m_pNewTarget[0]->m_pTex)
     {
       int nWidth = m_pNewTarget[0]->m_pTex->GetWidth();
       int nHeight = m_pNewTarget[0]->m_pTex->GetHeight();
       if (bAllowDIP && (m_CurViewport.nX || m_CurViewport.nY || m_CurViewport.nWidth!=nWidth || m_CurViewport.nHeight!=nHeight))
       {
         // Clear region
         FX_ClearRegion();
         bEntireClear = false;
       }
     }











  
    if (bEntireClear)
    {
			int nFlags = m_pNewTarget[0]->m_ClearFlags & ~D3DCLEAR_TARGET;
			if ( (m_pNewTarget[0]->m_pTarget!=NULL) && m_pNewTarget[0]->m_ClearFlags & D3DCLEAR_TARGET)
			{
#ifndef PS3
				for(int i=0;i<RT_STACK_WIDTH;++i)
					if(m_pNewTarget[i]->m_pTarget)
						m_pd3dDeviceContext->ClearRenderTargetView(m_pNewTarget[i]->m_pTarget, &m_pNewTarget[0]->m_ReqColor[0]);












#endif
			}
      if (nFlags == (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL))
      {
        m_pd3dDeviceContext->ClearDepthStencilView(m_pNewTarget[0]->m_pDepth, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, m_pNewTarget[0]->m_fReqDepth, m_pNewTarget[0]->m_nReqStencil);
      }
      else
      if (nFlags == D3DCLEAR_ZBUFFER)
        m_pd3dDeviceContext->ClearDepthStencilView(m_pNewTarget[0]->m_pDepth, D3D11_CLEAR_DEPTH, m_pNewTarget[0]->m_fReqDepth, 0);
      else
      if (nFlags == D3DCLEAR_STENCIL)
        m_pd3dDeviceContext->ClearDepthStencilView(m_pNewTarget[0]->m_pDepth, D3D11_CLEAR_STENCIL, m_pNewTarget[0]->m_fReqDepth, m_pNewTarget[0]->m_nReqStencil);
      else
      if (nFlags)
      {
        assert(0);
      }
    }
#endif
    m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTCleared++;
    CTexture *pRT = m_pNewTarget[0]->m_pTex;
    if (CV_r_stats == 13)
      EF_AddRTStat(pRT, m_pNewTarget[0]->m_ClearFlags, m_CurViewport.nWidth, m_CurViewport.nHeight);
    if (pRT)
    {
      if (m_pNewTarget[0]->m_ClearFlags & D3DCLEAR_TARGET)
        m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTClearedSize += pRT->GetDeviceDataSize();
      if (m_pNewTarget[0]->m_ClearFlags & D3DCLEAR_ZBUFFER)
        m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTClearedSize += pRT->GetWidth() * pRT->GetHeight() * 4;
    }
    else
    {
      if (m_pNewTarget[0]->m_ClearFlags & D3DCLEAR_TARGET)
        m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTClearedSize += m_width * m_height * 4;
      if (m_pNewTarget[0]->m_ClearFlags & D3DCLEAR_ZBUFFER)
        m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTClearedSize += m_width * m_height * 4;
      else
      if (m_pNewTarget[0]->m_ClearFlags & D3DCLEAR_STENCIL)
        m_RP.m_PS[m_RP.m_nProcessThreadID].m_RTClearedSize += m_width * m_height;
    }

    m_pNewTarget[0]->m_ClearFlags = 0;
  }

#if defined(DIRECT3D9) && !defined(XENON)
	if(bDirty)
	{
		int x,y,w,h;
		if (EF_GetScissorState(x,y,w,h))   //setting RTs silently disables scissor, restore state
		{
			RECT scRect;
			scRect.left		= x;
			scRect.right	= x+w;
			scRect.top		= y;
			scRect.bottom = y+h;
			m_pd3dDevice->SetScissorRect(&scRect);
			m_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
		}
	}
#endif
}

void CD3D9Renderer::FX_Commit(bool bAllowDIP)
{
  // Commit all changed shader parameters
  if (m_RP.m_nCommitFlags & FC_GLOBAL_PARAMS)
  {
    CHWShader_D3D::mfCommitParamsGlobal();
    m_RP.m_nCommitFlags &= ~FC_GLOBAL_PARAMS;
  }
#if defined(PS3) || defined(DIRECT3D10)
  if (m_RP.m_nCommitFlags & FC_MATERIAL_PARAMS)
  {
    CHWShader_D3D::mfCommitParamsMaterial();
    m_RP.m_nCommitFlags &= ~FC_MATERIAL_PARAMS;
  }
#endif
  CHWShader_D3D::mfCommitParams();

  // Commit all changed RT's
  if (m_RP.m_nCommitFlags & FC_TARGETS)
    FX_SetActiveRenderTargets(bAllowDIP);




}


// Set current geometry culling modes
void CD3D9Renderer::D3DSetCull(ECull eCull, bool bSkipMirrorCull)
{ 
	FUNCTION_PROFILER_RENDER_FLAT
  if (eCull != eCULL_None && !bSkipMirrorCull)
  {
    if (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & (RBPF_MIRRORCULL))
      eCull = (eCull == eCULL_Back) ? eCULL_Front : eCULL_Back;
  }

  if (eCull == m_RP.m_eCull)
    return;

#if defined (DIRECT3D9)
  if (eCull == eCULL_None)
    m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
  else
  {
    if (eCull == eCULL_Back)
      m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
    else
      m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
  }
#elif defined (DIRECT3D10)
  SStateRaster RS = m_StatesRS[m_nCurStateRS];

  RS.Desc.FrontCounterClockwise = true;

	if (eCull == eCULL_None)
		RS.Desc.CullMode = D3D11_CULL_NONE;
	else
	{
		if (eCull == eCULL_Back)
		{
			RS.Desc.CullMode = D3D11_CULL_BACK;
		}
		else
		{
			RS.Desc.CullMode = D3D11_CULL_FRONT;
		}
	}
  SetRasterState(&RS);
#endif
  m_RP.m_eCull = eCull;
}

#if defined(DIRECT3D10)
uint8 g_StencilFuncLookup[8] = 
{
	D3D11_COMPARISON_ALWAYS,				// FSS_STENCFUNC_ALWAYS   0x0
	D3D11_COMPARISON_NEVER,					// FSS_STENCFUNC_NEVER    0x1
	D3D11_COMPARISON_LESS,					// FSS_STENCFUNC_LESS     0x2
	D3D11_COMPARISON_LESS_EQUAL,		// FSS_STENCFUNC_LEQUAL   0x3
	D3D11_COMPARISON_GREATER,				// FSS_STENCFUNC_GREATER  0x4
	D3D11_COMPARISON_GREATER_EQUAL,	// FSS_STENCFUNC_GEQUAL   0x5
	D3D11_COMPARISON_EQUAL,					// FSS_STENCFUNC_EQUAL    0x6
	D3D11_COMPARISON_NOT_EQUAL			// FSS_STENCFUNC_NOTEQUAL 0x7
};

uint8 g_StencilOpLookup[8] =
{
	D3D11_STENCIL_OP_KEEP,					// FSS_STENCOP_KEEP    0x0
	D3D11_STENCIL_OP_REPLACE,				// FSS_STENCOP_REPLACE 0x1
	D3D11_STENCIL_OP_INCR_SAT,			// FSS_STENCOP_INCR    0x2
	D3D11_STENCIL_OP_DECR_SAT,			// FSS_STENCOP_DECR    0x3
	D3D11_STENCIL_OP_ZERO,					// FSS_STENCOP_ZERO    0x4
	D3D11_STENCIL_OP_INCR,					// FSS_STENCOP_INCR_WRAP 0x5
	D3D11_STENCIL_OP_DECR,					// FSS_STENCOP_DECR_WRAP 0x6
	D3D11_STENCIL_OP_INVERT					// FSS_STENCOP_INVERT 0x7
};
#endif

void CRenderer::FX_SetStencilState(int st, uint32 nStencRef, uint32 nStencMask, uint32 nStencWriteMask, bool bForceFullReadMask )
{
  FUNCTION_PROFILER_RENDER_FLAT

#if defined(DIRECT3D10)
	PrefetchLine(g_StencilFuncLookup, 0);
#endif

	const uint32 nPersFlags2 = m_RP.m_PersFlags2;

  // Note to NickK - do we use this at all ? Masking is not supported for RSX
  if (!bForceFullReadMask && !(nPersFlags2 & RBPF2_MASKSTATIC))
  {
    nStencMask &= ~BIT_STENCIL_STATIC;
  }

  nStencRef |= m_RP.m_CurStencilRefAndMask;

#if defined (DIRECT3D9)
  LPDIRECT3DDEVICE9 dv = gcpRendD3D->GetD3DDevice();
  if (nStencRef != m_RP.m_CurStencRef)
  {
    m_RP.m_CurStencRef = nStencRef;
    dv->SetRenderState(D3DRS_STENCILREF, nStencRef);
  }
  if (nStencMask != m_RP.m_CurStencMask)
  {
    m_RP.m_CurStencMask = nStencMask;
    dv->SetRenderState(D3DRS_STENCILMASK, nStencMask);
  }
  if (nStencWriteMask != m_RP.m_CurStencWriteMask)
  {
    m_RP.m_CurStencWriteMask = nStencWriteMask;
    dv->SetRenderState(D3DRS_STENCILWRITEMASK, nStencWriteMask);
  }

  int Changed = st ^ m_RP.m_CurStencilState;
  if (!Changed)
    return;
  if (Changed & FSS_STENCIL_TWOSIDED)
  {
    if (st & FSS_STENCIL_TWOSIDED)
      dv->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
    else
      dv->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
  }
  if (Changed & FSS_STENCFUNC_MASK)
  {
    int nCurFunc = st & FSS_STENCFUNC_MASK;
    switch(nCurFunc)
    {
    case FSS_STENCFUNC_ALWAYS:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
      break;
    case FSS_STENCFUNC_NEVER:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NEVER);
      break;
    case FSS_STENCFUNC_LESS:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESS);
      break;
    case FSS_STENCFUNC_LEQUAL:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL);
      break;
    case FSS_STENCFUNC_GREATER:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATER);
      break;
    case FSS_STENCFUNC_GEQUAL:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL);
      break;
    case FSS_STENCFUNC_EQUAL:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
      break;
    case FSS_STENCFUNC_NOTEQUAL:
      dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL);
      break;
    default:
      assert(false);
    }
  }
  if (Changed & FSS_STENCFAIL_MASK)
  {
    int nCurOp = (st & FSS_STENCFAIL_MASK);
    switch(nCurOp >> FSS_STENCFAIL_SHIFT)
    {
    case FSS_STENCOP_KEEP:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
      break;
    case FSS_STENCOP_REPLACE:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
      break;
    case FSS_STENCOP_INCR:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INCRSAT);
      break;
    case FSS_STENCOP_DECR:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_DECRSAT);
      break;
    case FSS_STENCOP_INCR_WRAP:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INCR);
      break;
    case FSS_STENCOP_DECR_WRAP:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_DECR);
      break;
    case FSS_STENCOP_ZERO:
      dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO);
      break;
		case FSS_STENCOP_INVERT:
			dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INVERT);
			break;
    default:
      assert(false);
    }
  }
  if (Changed & FSS_STENCZFAIL_MASK)
  {
    int nCurOp = (st & FSS_STENCZFAIL_MASK);
    switch(nCurOp >> FSS_STENCZFAIL_SHIFT)
    {
    case FSS_STENCOP_KEEP:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
      break;
    case FSS_STENCOP_REPLACE:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
      break;
    case FSS_STENCOP_INCR:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCRSAT);
      break;
    case FSS_STENCOP_DECR:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_DECRSAT);
      break;
    case FSS_STENCOP_INCR_WRAP:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR);
      break;
    case FSS_STENCOP_DECR_WRAP:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR);
      break;
    case FSS_STENCOP_ZERO:
      dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_ZERO);
      break;
		case FSS_STENCOP_INVERT:
			dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INVERT);
			break;
    default:
      assert(false);
    }
  }
  if (Changed & FSS_STENCPASS_MASK)
  {
    int nCurOp = (st & FSS_STENCPASS_MASK);
    switch(nCurOp >> FSS_STENCPASS_SHIFT)
    {
    case FSS_STENCOP_KEEP:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
      break;
    case FSS_STENCOP_REPLACE:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
      break;
    case FSS_STENCOP_INCR:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCRSAT);
      break;
    case FSS_STENCOP_DECR:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECRSAT);
      break;
    case FSS_STENCOP_INCR_WRAP:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
      break;
    case FSS_STENCOP_DECR_WRAP:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR);
      break;
    case FSS_STENCOP_ZERO:
      dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO);
      break;
		case FSS_STENCOP_INVERT:
			dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INVERT);
			break;
    default:
      assert(false);
    }
  }

  if (Changed & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT))
  {
    int nCurFunc = (st & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT));
    switch(nCurFunc >> FSS_CCW_SHIFT)
    {
    case FSS_STENCFUNC_ALWAYS:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS);
      break;
    case FSS_STENCFUNC_NEVER:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_NEVER);
      break;
    case FSS_STENCFUNC_LESS:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_LESS);
      break;
    case FSS_STENCFUNC_LEQUAL:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_LESSEQUAL);
      break;
    case FSS_STENCFUNC_GREATER:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_GREATER);
      break;
    case FSS_STENCFUNC_GEQUAL:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_GREATEREQUAL);
      break;
    case FSS_STENCFUNC_EQUAL:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_EQUAL);
      break;
    case FSS_STENCFUNC_NOTEQUAL:
      dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_NOTEQUAL);
      break;
    default:
      assert(false);
    }
  }
  if (Changed & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT))
  {
    int nCurOp = (st & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT));
    switch(nCurOp >> (FSS_STENCFAIL_SHIFT+FSS_CCW_SHIFT))
    {
    case FSS_STENCOP_KEEP:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP);
      break;
    case FSS_STENCOP_REPLACE:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_REPLACE);
      break;
    case FSS_STENCOP_INCR:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INCRSAT);
      break;
    case FSS_STENCOP_DECR:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_DECRSAT);
      break;
    case FSS_STENCOP_INCR_WRAP:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INCR);
      break;
    case FSS_STENCOP_DECR_WRAP:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_DECR);
      break;
    case FSS_STENCOP_ZERO:
      dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_ZERO);
      break;
		case FSS_STENCOP_INVERT:
			dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INVERT);
			break;
    default:
      assert(false);
    }
  }
  if (Changed & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT))
  {
    int nCurOp = (st & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT));
    switch(nCurOp >> (FSS_STENCZFAIL_SHIFT+FSS_CCW_SHIFT))
    {
    case FSS_STENCOP_KEEP:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP);
      break;
    case FSS_STENCOP_REPLACE:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_REPLACE);
      break;
    case FSS_STENCOP_INCR:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INCRSAT);
      break;
    case FSS_STENCOP_DECR:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECRSAT);
      break;
    case FSS_STENCOP_INCR_WRAP:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INCR);
      break;
    case FSS_STENCOP_DECR_WRAP:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECR);
      break;
    case FSS_STENCOP_ZERO:
      dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_ZERO);
      break;
		case FSS_STENCOP_INVERT:
			dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INVERT);
			break;
    default:
      assert(false);
    }
  }
  if (Changed & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT))
  {
    int nCurOp = (st & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT));
    switch(nCurOp >> (FSS_STENCPASS_SHIFT+FSS_CCW_SHIFT))
    {
    case FSS_STENCOP_KEEP:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP);
      break;
    case FSS_STENCOP_REPLACE:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_REPLACE);
      break;
    case FSS_STENCOP_INCR:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INCRSAT);
      break;
    case FSS_STENCOP_DECR:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECRSAT);
      break;
    case FSS_STENCOP_INCR_WRAP:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INCR);
      break;
    case FSS_STENCOP_DECR_WRAP:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECR);
      break;
    case FSS_STENCOP_ZERO:
      dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_ZERO);
      break;
		case FSS_STENCOP_INVERT:
			dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INVERT);
			break;
    default:
      assert(false);
    }
  }
#elif defined (DIRECT3D10)
  SStateDepth DS = gcpRendD3D->m_StatesDP[gcpRendD3D->m_nCurStateDP];
  DS.Desc.StencilReadMask = nStencMask;
  DS.Desc.StencilWriteMask = nStencWriteMask;

  int nCurFunc = st & FSS_STENCFUNC_MASK;
	DS.Desc.FrontFace.StencilFunc		= (D3D11_COMPARISON_FUNC)g_StencilFuncLookup[nCurFunc];

	int nCurOp = (st & FSS_STENCFAIL_MASK) >> FSS_STENCFAIL_SHIFT;
	DS.Desc.FrontFace.StencilFailOp	= (D3D11_STENCIL_OP)g_StencilOpLookup[nCurOp];
  
  nCurOp = (st & FSS_STENCZFAIL_MASK) >> FSS_STENCZFAIL_SHIFT;
	DS.Desc.FrontFace.StencilDepthFailOp	= (D3D11_STENCIL_OP)g_StencilOpLookup[nCurOp];

  nCurOp = (st & FSS_STENCPASS_MASK) >> FSS_STENCPASS_SHIFT;
	DS.Desc.FrontFace.StencilPassOp	= (D3D11_STENCIL_OP)g_StencilOpLookup[nCurOp];
  
  if (!(st & FSS_STENCIL_TWOSIDED))
	{
		DS.Desc.BackFace = DS.Desc.FrontFace;
	}
	else
	{
		nCurFunc = (st & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT)) >> FSS_CCW_SHIFT;
		DS.Desc.BackFace.StencilFunc		=	(D3D11_COMPARISON_FUNC)g_StencilFuncLookup[nCurFunc];
	  
		nCurOp = (st & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT)) >> (FSS_STENCFAIL_SHIFT+FSS_CCW_SHIFT);
		DS.Desc.BackFace.StencilFailOp	= (D3D11_STENCIL_OP)g_StencilOpLookup[nCurOp];
	  
		nCurOp = (st & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT)) >> (FSS_STENCZFAIL_SHIFT+FSS_CCW_SHIFT);
		DS.Desc.BackFace.StencilDepthFailOp	= (D3D11_STENCIL_OP)g_StencilOpLookup[nCurOp];
	  
		nCurOp = (st & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT)) >> (FSS_STENCPASS_SHIFT+FSS_CCW_SHIFT);
		DS.Desc.BackFace.StencilPassOp	= (D3D11_STENCIL_OP)g_StencilOpLookup[nCurOp];
	}

  m_RP.m_CurStencRef = nStencRef;
  m_RP.m_CurStencMask = nStencMask;
  m_RP.m_CurStencWriteMask = nStencWriteMask;

  gcpRendD3D->SetDepthState(&DS, nStencRef);
#endif





  m_RP.m_CurStencilState = st;
}

void CD3D9Renderer::EF_Scissor(bool bEnable, int sX, int sY, int sWdt, int sHgt)
{
	FUNCTION_PROFILER_RENDER_FLAT
  if (!CV_r_scissor || (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN))
    return;
#if defined (DIRECT3D9)
  RECT scRect;
  if (bEnable)
  {
    if (sX != m_sPrevX || sY != m_sPrevY || sWdt != m_sPrevWdt || sHgt != m_sPrevHgt)
    {
      m_sPrevX = sX;
      m_sPrevY = sY;
      m_sPrevWdt = sWdt;
      m_sPrevHgt = sHgt;
      scRect.left = sX;
      scRect.right = sX + sWdt;
      scRect.top = sY;
      scRect.bottom = sY + sHgt;
      m_pd3dDevice->SetScissorRect(&scRect);
    }
    if (bEnable != m_bsPrev)
    {
      m_bsPrev = bEnable;
      m_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
    }
  }
  else
  {
    if (bEnable != m_bsPrev)
    {
      m_bsPrev = bEnable;
      m_sPrevWdt = 0;
      m_sPrevHgt = 0;
      m_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
    }
  }
#elif defined (DIRECT3D10)
  D3D11_RECT scRect;
  if (bEnable)
  {
    if (sX != m_sPrevX || sY != m_sPrevY || sWdt != m_sPrevWdt || sHgt != m_sPrevHgt)
    {
      m_sPrevX = sX;
      m_sPrevY = sY;
      m_sPrevWdt = sWdt;
      m_sPrevHgt = sHgt;
      scRect.left = sX;
      scRect.top = sY;

// ps3 handles scissors with width/height only




      scRect.right = sX + sWdt;      
      scRect.bottom = sY + sHgt;


      m_pd3dDeviceContext->RSSetScissorRects(1, &scRect);
    }
    if (bEnable != m_bsPrev)
    {
      m_bsPrev = bEnable;
      SStateRaster RS = m_StatesRS[m_nCurStateRS];
      RS.Desc.ScissorEnable = bEnable;
      SetRasterState(&RS);
    }
  }
  else
  {
    if (bEnable != m_bsPrev)
    {
      m_bsPrev = bEnable;
      m_sPrevWdt = 0;
      m_sPrevHgt = 0;
      SStateRaster RS = m_StatesRS[m_nCurStateRS];
      RS.Desc.ScissorEnable = bEnable;
      SetRasterState(&RS);
    }








  }
#endif
}

bool CD3D9Renderer::EF_GetScissorState(int& sX, int& sY, int& sWdt, int& sHgt)
{
	if (!CV_r_scissor || (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN))
		return false;

	sX = m_sPrevX;
	sY = m_sPrevY;
	sWdt = m_sPrevWdt;
	sHgt = m_sPrevHgt;
	return m_bsPrev;
}

void CD3D9Renderer::FX_FogCorrection()
{
	if (m_RP.m_nPassGroupID <= EFSLIST_DECAL)
	{
		uint32 uBlendFlags = m_RP.m_CurState & GS_BLEND_MASK;
		switch ( uBlendFlags )
		{
		case GS_BLSRC_ONE | GS_BLDST_ONE:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_DSTALPHA | GS_BLDST_ONE:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_DSTCOL | GS_BLDST_SRCCOL:
			{
				static ColorF pColGrey = ColorF(0.5f, 0.5f, 0.5f, 1.0f);
				EF_SetFogColor(pColGrey);
				break;
			}		
		case GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCCOL:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_ZERO | GS_BLDST_ONEMINUSSRCCOL:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_SRCALPHA | GS_BLDST_ONE:
		case GS_BLSRC_SRCALPHA_A_ZERO | GS_BLDST_ONE:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_ZERO | GS_BLDST_ONE:
			EF_SetFogColor(Col_Black);
			break;
		case GS_BLSRC_DSTCOL | GS_BLDST_ZERO:
			EF_SetFogColor(Col_White);
			break;
		default:
			EF_SetFogColor(m_RP.m_TI[m_RP.m_nProcessThreadID].m_FS.m_FogColor);
			break;
		}
	}
	else
	{
		EF_SetFogColor(m_RP.m_TI[m_RP.m_nProcessThreadID].m_FS.m_FogColor);
	}
}

void CD3D9Renderer::FX_SetHiZState(int newHiZState, int curState, int curStencilState)
{




















































































  return;
}

// Set current render states 
void CD3D9Renderer::FX_SetState(int st, int AlphaRef, int RestoreState)
{
	FUNCTION_PROFILER_RENDER_FLAT
  int Changed;

  st |= m_RP.m_StateOr;
  st &= m_RP.m_StateAnd;
  Changed = st ^ m_RP.m_CurState;
  Changed |= RestoreState;




  if (!Changed && (AlphaRef==-1 || AlphaRef==m_RP.m_CurAlphaRef))  

    return;

  //PROFILE_FRAME(State_RStates);

#if defined (DIRECT3D9)
  int src, dst;
  LPDIRECT3DDEVICE9 dv = gcpRendD3D->GetD3DDevice();
#ifndef _RELEASE
  m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumStateChanges++;
#endif
  if (Changed & GS_DEPTHFUNC_MASK)
  {
    switch (st & GS_DEPTHFUNC_MASK)
    {
#if defined(INVERT_DEPTH_RANGE)
    case GS_DEPTHFUNC_EQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
      break;
    case GS_DEPTHFUNC_LEQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL);
      break;
    case GS_DEPTHFUNC_GREAT:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
      break;
    case GS_DEPTHFUNC_LESS:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER);
      break;
    case GS_DEPTHFUNC_NOTEQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL);
      break;
    case GS_DEPTHFUNC_GEQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
      break;
#else 
    case GS_DEPTHFUNC_EQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
      break;
    case GS_DEPTHFUNC_LEQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
      break;
    case GS_DEPTHFUNC_GREAT:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER);
      break;
    case GS_DEPTHFUNC_LESS:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
      break;
    case GS_DEPTHFUNC_NOTEQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL);
      break;
    case GS_DEPTHFUNC_GEQUAL:
      dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL);
      break;
#endif

    }
    



  }

  if (Changed & (GS_WIREFRAME|GS_POINTRENDERING))
  {
    if (st & GS_POINTRENDERING)
    {
      dv->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT);
    }
    else if (st & GS_WIREFRAME)
    {
      dv->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
    }
    else
    {
      dv->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
    }
  }

	if (Changed & GS_COLMASK_MASK)
  {
		uint32 nMask = 0xfffffff0 | ((st & GS_COLMASK_MASK) >> GS_COLMASK_SHIFT);
		nMask = (~nMask) & 0xf;
		dv->SetRenderState(D3DRS_COLORWRITEENABLE, nMask);
		dv->SetRenderState(D3DRS_COLORWRITEENABLE1, nMask);
		dv->SetRenderState(D3DRS_COLORWRITEENABLE2, nMask);
		dv->SetRenderState(D3DRS_COLORWRITEENABLE3, nMask);
	}

	bool bHiPrecisionBlend = false;
  
  if (Changed & GS_BLEND_MASK)
  {
		// Need to disable color write to MRTs for shadow map alpha blending (not supported by all hw)
		if ((m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN) && m_pNewTarget[1])
		{
			if (st & GS_BLEND_MASK)
			{
				dv->SetRenderState(D3DRS_COLORWRITEENABLE1, 0);
				dv->SetRenderState(D3DRS_COLORWRITEENABLE2, 0);
				dv->SetRenderState(D3DRS_COLORWRITEENABLE3, 0);
			}
			else
			{
				uint32 nMask = 0xfffffff0 | ((st & GS_COLMASK_MASK) >> GS_COLMASK_SHIFT);
				nMask = (~nMask) & 0xf;
				dv->SetRenderState(D3DRS_COLORWRITEENABLE1, nMask);
				dv->SetRenderState(D3DRS_COLORWRITEENABLE2, nMask);
				dv->SetRenderState(D3DRS_COLORWRITEENABLE3, nMask);
			}
		}

    if (st & GS_BLEND_MASK)
    {
			int srca = 0, dsta = 0;
			D3DBLENDOP blendOperation = D3DBLENDOP_ADD;

      if (CV_r_measureoverdraw && (m_RP.m_nRendFlags & SHDF_ALLOWHDR))
      {
        st = (st & ~GS_BLEND_MASK) | (GS_BLSRC_ONE | GS_BLDST_ONE);
        st &= ~GS_ALPHATEST_MASK;
      }

      // Source factor
      switch (st & GS_BLSRC_MASK)
      {
      case GS_BLSRC_ZERO:
        src = srca = D3DBLEND_ZERO;
        break;
      case GS_BLSRC_ONE:
        src = srca = D3DBLEND_ONE;
        break;
      case GS_BLSRC_DSTCOL:
        src = srca = D3DBLEND_DESTCOLOR;
        break;
      case GS_BLSRC_ONEMINUSDSTCOL:
        src = srca = D3DBLEND_INVDESTCOLOR;
        break;
      case GS_BLSRC_SRCALPHA:
        src = srca = D3DBLEND_SRCALPHA;
        break;
      case GS_BLSRC_ONEMINUSSRCALPHA:
        src = srca = D3DBLEND_INVSRCALPHA;
        break;
      case GS_BLSRC_DSTALPHA:
        src = srca = D3DBLEND_DESTALPHA;
        break;
      case GS_BLSRC_ONEMINUSDSTALPHA:
        src = srca = D3DBLEND_INVDESTALPHA;
        break;
      case GS_BLSRC_ALPHASATURATE:
        src = srca = D3DBLEND_SRCALPHASAT;
        break;
			case GS_BLSRC_SRCALPHA_A_ZERO:
				src = D3DBLEND_SRCALPHA;
				srca = D3DBLEND_ZERO;
				break;
      default:
        iLog->Log("CD3D9Renderer::SetState: invalid src blend state bits '%d'", st & GS_BLSRC_MASK);
        break;
      }

      //Destination factor
      switch (st & GS_BLDST_MASK)
      {
      case GS_BLDST_ZERO:
        dst = dsta = D3DBLEND_ZERO;
        break;
      case GS_BLDST_ONE:
        dst = dsta = D3DBLEND_ONE;
        break;
      case GS_BLDST_SRCCOL:
        dst = dsta = D3DBLEND_SRCCOLOR;
        break;
      case GS_BLDST_ONEMINUSSRCCOL:
        dst = dsta = D3DBLEND_INVSRCCOLOR;
        if (m_nHDRType == 1 && (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_HDR))
            dst = dsta = D3DBLEND_ONE;
        break;
      case GS_BLDST_SRCALPHA:
        dst = dsta = D3DBLEND_SRCALPHA;
        break;
      case GS_BLDST_ONEMINUSSRCALPHA:
        dst = dsta = D3DBLEND_INVSRCALPHA;
        break;
      case GS_BLDST_DSTALPHA:
        dst = dsta = D3DBLEND_DESTALPHA;
        break;
      case GS_BLDST_ONEMINUSDSTALPHA:
        dst = dsta = D3DBLEND_INVDESTALPHA;
        break;
			case GS_BLDST_ONE_A_ZERO:
				dst = D3DBLEND_ONE;
				dsta = D3DBLEND_ZERO;
				break;
      default:
        iLog->Log("CD3D9Renderer::SetState: invalid dst blend state bits '%d'", st & GS_BLDST_MASK);
        break;
      }
			//Blending operation
			if (Changed & GS_BLEND_OP_MASK)
			{
				switch (st & GS_BLEND_OP_MASK)
				{
				case GS_BLOP_MAX:
					blendOperation = D3DBLENDOP_MAX;
					break;
				default:
					blendOperation = D3DBLENDOP_ADD;
					break;
				}
				dv->SetRenderState(D3DRS_BLENDOP,  blendOperation);
			}

      if ( !(m_RP.m_CurState & GS_BLEND_MASK) )
        dv->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

			dv->SetRenderState(D3DRS_SRCBLEND,  src);
      dv->SetRenderState(D3DRS_DESTBLEND, dst);
			if ((src ^ srca) | (dst ^ dsta))
			{
				dv->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
				dv->SetRenderState(D3DRS_SRCBLENDALPHA,  srca);
				dv->SetRenderState(D3DRS_DESTBLENDALPHA, dsta);
			}
			else
				dv->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
      




		}
		else
		{
			dv->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
		}
	}































  if (Changed & GS_DEPTHWRITE)
  {
    if (st & GS_DEPTHWRITE)
      dv->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
    else
      dv->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);



  }

  if (Changed & GS_NODEPTHTEST)
  {
    if (st & GS_NODEPTHTEST)
    {
      dv->SetRenderState(D3DRS_ZENABLE, FALSE);
    }
    else
    {
      dv->SetRenderState(D3DRS_ZENABLE, TRUE);
    }



  }

	if ((Changed & GS_STENCIL) && !(m_RP.m_PersFlags2 & RBPF2_LOCKSTENCIL))
  {
    if (st & GS_STENCIL)
      dv->SetRenderState(D3DRS_STENCILENABLE, TRUE);
    else
      dv->SetRenderState(D3DRS_STENCILENABLE, FALSE);



  }

  {
#if !defined(XENON) && !defined(PS3)
    // Disable AT for general passes
    if (SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID] == 1 && m_RP.m_nPassGroupID == EFSLIST_GENERAL && !(m_RP.m_nBatchFilter & (FB_Z|FB_GLOW)) && CV_r_usezpass)
    {
      if (m_RP.m_CurState & GS_ALPHATEST_MASK)
        dv->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
      st &= ~GS_ALPHATEST_MASK;
    }
    else
#endif
    {
      if ((st & GS_ALPHATEST_MASK) && m_RP.m_CurAlphaRef != AlphaRef)
      {
        //assert(AlphaRef>=0 && AlphaRef<255);
        m_RP.m_CurAlphaRef = AlphaRef;
        dv->SetRenderState(D3DRS_ALPHAREF, AlphaRef);
      }
      if ((st ^ m_RP.m_CurState) & GS_ALPHATEST_MASK)
      {
        if (st & GS_ALPHATEST_MASK)
        {
          if (!(m_RP.m_CurState & GS_ALPHATEST_MASK))
            dv->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
          switch (st & GS_ALPHATEST_MASK)
          {
          case GS_ALPHATEST_GREATER:
            dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
            break;
          case GS_ALPHATEST_LESS:
            dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);
            break;
          case GS_ALPHATEST_GEQUAL:
            dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
            break;
          case GS_ALPHATEST_LEQUAL:
            dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL);
            break;
          }
        }
        else
          dv->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
      }
    }
  }
#elif defined (DIRECT3D10)
#ifndef _RELEASE
  m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumStateChanges++;
#endif
  if (m_StatesBL.size()==0 || m_StatesDP.size()==0 || m_StatesRS.size()==0)
    ResetToDefault(); 
  SStateDepth DS = m_StatesDP[m_nCurStateDP];
  SStateBlend BS = m_StatesBL[m_nCurStateBL];
  SStateRaster RS = m_StatesRS[m_nCurStateRS];
  bool bDirtyDS = false;
  bool bDirtyBS = false;
  bool bDirtyRS = false;

  if (Changed & GS_DEPTHFUNC_MASK)
  {
    bDirtyDS = true;
    switch (st & GS_DEPTHFUNC_MASK)
    {
    case GS_DEPTHFUNC_EQUAL:
      DS.Desc.DepthFunc = D3D11_COMPARISON_EQUAL;
      break;
    case GS_DEPTHFUNC_LEQUAL:
      DS.Desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
      break;
    case GS_DEPTHFUNC_GREAT:
      DS.Desc.DepthFunc = D3D11_COMPARISON_GREATER;
      break;
    case GS_DEPTHFUNC_LESS:
      DS.Desc.DepthFunc = D3D11_COMPARISON_LESS;
      break;
    case GS_DEPTHFUNC_NOTEQUAL:
      DS.Desc.DepthFunc = D3D11_COMPARISON_NOT_EQUAL;
      break;
    case GS_DEPTHFUNC_GEQUAL:
      DS.Desc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL;
      break;
    }
  }

	if (Changed & (GS_WIREFRAME|GS_POINTRENDERING))
	{
		bDirtyRS = true;
		if (st & GS_WIREFRAME)
			RS.Desc.FillMode = D3D11_FILL_WIREFRAME;





		else      
			RS.Desc.FillMode = D3D11_FILL_SOLID;
	}

  if (Changed & GS_COLMASK_MASK)
  {
    bDirtyBS = true;
    uint32 nMask = 0xfffffff0 | ((st & GS_COLMASK_MASK) >> GS_COLMASK_SHIFT);
		nMask = (~nMask) & 0xf;
		BS.Desc.RenderTarget[0].RenderTargetWriteMask = nMask;
		BS.Desc.RenderTarget[1].RenderTargetWriteMask = nMask;
		BS.Desc.RenderTarget[2].RenderTargetWriteMask = nMask;
		BS.Desc.RenderTarget[3].RenderTargetWriteMask = nMask;
  }

  if (Changed & GS_BLEND_MASK) 
  {
		bDirtyBS = true;
		if (st & GS_BLEND_MASK)
		{
      if (CV_r_measureoverdraw && (m_RP.m_nRendFlags & SHDF_ALLOWHDR))
      {
        st = (st & ~GS_BLEND_MASK) | (GS_BLSRC_ONE | GS_BLDST_ONE);
        st &= ~GS_ALPHATEST_MASK;
      }

			// todo: add separate alpha blend support for mrt
			for (size_t i=0; i<4; ++i)
				BS.Desc.RenderTarget[i].BlendEnable = TRUE;

			// Source factor
			switch (st & GS_BLSRC_MASK)
			{
			case GS_BLSRC_ZERO:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ZERO;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
				break;
			case GS_BLSRC_ONE:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
				break;
			case GS_BLSRC_DSTCOL:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_COLOR;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
				break;
			case GS_BLSRC_ONEMINUSDSTCOL:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
				break;
			case GS_BLSRC_SRCALPHA:




        BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
        BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;

				break;
			case GS_BLSRC_ONEMINUSSRCALPHA:




        BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC_ALPHA;
        BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;

				break;
			case GS_BLSRC_DSTALPHA:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_ALPHA;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
				break;
			case GS_BLSRC_ONEMINUSDSTALPHA:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_ALPHA;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
				break;
			case GS_BLSRC_ALPHASATURATE:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA_SAT;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA_SAT;
				break;
			case GS_BLSRC_SRCALPHA_A_ZERO:
				BS.Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
				BS.Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
				break;
			default:
				iLog->Log("CD3D9Renderer::SetState: invalid src blend state bits '%d'", st & GS_BLSRC_MASK);
				break;
			}

			//Destination factor
			switch (st & GS_BLDST_MASK)
			{
			case GS_BLDST_ZERO:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
				break;
			case GS_BLDST_ONE:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
				break;
			case GS_BLDST_SRCCOL:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_COLOR;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
				break;
			case GS_BLDST_ONEMINUSSRCCOL:
				if (m_nHDRType == 1 && (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_HDR))
				{
					BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
					BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
				}
				else
				{
					BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
					BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
				}
				break;
			case GS_BLDST_SRCALPHA:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC_ALPHA;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
				break;
			case GS_BLDST_ONEMINUSSRCALPHA:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
				break;
			case GS_BLDST_DSTALPHA:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_DEST_ALPHA;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
				break;
			case GS_BLDST_ONEMINUSDSTALPHA:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_DEST_ALPHA;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
				break;
			case GS_BLDST_ONE_A_ZERO:
				BS.Desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
				BS.Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
				break;
			default:
				iLog->Log("CD3D9Renderer::SetState: invalid dst blend state bits '%d'", st & GS_BLDST_MASK);
				break;
			}

			//Blending operation
			D3D11_BLEND_OP blendOperation = D3D11_BLEND_OP_ADD;
			switch (st & GS_BLEND_OP_MASK)
			{
			case GS_BLOP_MAX:
				blendOperation = D3D11_BLEND_OP_MAX;
				break;
			}

			// todo: add separate alpha blend support for mrt
			for(size_t i=0; i<4; ++i)
			{
				BS.Desc.RenderTarget[i].BlendOp = blendOperation;
				BS.Desc.RenderTarget[i].BlendOpAlpha = blendOperation;
			}
    }
    else
    {
      // todo: add separate alpha blend support for mrt
			for (size_t i=0; i<4; ++i)
				BS.Desc.RenderTarget[i].BlendEnable = FALSE;
    }

		// Need to disable color write to MRTs for shadow map alpha blending (not supported by all hw)
		if ((m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN) && m_pNewTarget[1])
		{
			bDirtyBS = true;
			uint32 nMask = 0xfffffff0 | ((st & GS_COLMASK_MASK) >> GS_COLMASK_SHIFT);
			nMask = (~nMask) & 0xf;
			BS.Desc.RenderTarget[0].RenderTargetWriteMask = nMask;
			if(st & GS_BLEND_MASK)
			{
				BS.Desc.IndependentBlendEnable = TRUE;
				for(size_t i=1; i<4; ++i)
				{
					BS.Desc.RenderTarget[i].RenderTargetWriteMask = 0;
					BS.Desc.RenderTarget[i].BlendEnable = FALSE;
				}
			}
			else
			{
				BS.Desc.IndependentBlendEnable = FALSE;
				for(size_t i=1;i<8;++i)
				{
					BS.Desc.RenderTarget[i].RenderTargetWriteMask = nMask;
					BS.Desc.RenderTarget[i].BlendEnable = TRUE;
				}
			}
		}
  }

  if (Changed & GS_DEPTHWRITE)
  {
    bDirtyDS = true;
    if (st & GS_DEPTHWRITE)
      DS.Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    else
      DS.Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
  }

  if (Changed & GS_NODEPTHTEST)
  {
    bDirtyDS = true;
    if (st & GS_NODEPTHTEST)
      DS.Desc.DepthEnable = FALSE;
    else
      DS.Desc.DepthEnable = TRUE;
  }

  if (Changed & GS_STENCIL)
  {
    bDirtyDS = true;
    if (st & GS_STENCIL)
      DS.Desc.StencilEnable = TRUE;
    else
      DS.Desc.StencilEnable = FALSE;
  }

  {
    // Alpha test must be handled in shader in D3D10 API
    if ( ((st ^ m_RP.m_CurState) & GS_ALPHATEST_MASK)	|| ((st & GS_ALPHATEST_MASK) && (m_RP.m_CurAlphaRef != AlphaRef && AlphaRef != -1)))
    {
			if (st & GS_ALPHATEST_MASK)
				m_RP.m_CurAlphaRef = AlphaRef;






















    }
  }

	if (bDirtyDS)
    SetDepthState(&DS, m_nCurStencRef);
  if (bDirtyRS)
    SetRasterState(&RS);
  if (bDirtyBS)
    SetBlendState(&BS);
#endif

  m_RP.m_CurState = st;
}

void CD3D9Renderer::FX_ZState(uint32& nState)
{
  // We cannot use z-prepass results with predicated tiling on Xenon





	int nNewState = nState;
  assert(m_RP.m_pRootTechnique);		// cannot be 0 here
  
	if ((m_RP.m_pRootTechnique->m_Flags & (FHF_WASZWRITE | FHF_POSITION_INVARIANT)) 
				&& m_RP.m_nPassGroupID==EFSLIST_GENERAL
				&& SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID] == 1
				&& CV_r_usezpass)
	{
		if((m_RP.m_nBatchFilter & (FB_GENERAL|FB_MULTILAYERS)) && (m_RP.m_nRendFlags & (SHDF_ALLOWHDR | SHDF_ALLOWPOSTPROCESS)))
		{
			if (!(m_RP.m_pRootTechnique->m_Flags & FHF_POSITION_INVARIANT))
				nNewState |= GS_DEPTHFUNC_EQUAL;
			nNewState &= ~(GS_DEPTHWRITE | GS_ALPHATEST_MASK);
		}

		if ((m_RP.m_nBatchFilter & FB_SCATTER))
		{
			if (!(m_RP.m_pRootTechnique->m_Flags & FHF_POSITION_INVARIANT))
				nNewState |= GS_NODEPTHTEST;
			nNewState &= ~(GS_DEPTHWRITE | GS_ALPHATEST_MASK);
		}

		nState = nNewState;
	}	
}

void CD3D9Renderer::FX_HairState(uint32& nState, const SShaderPass *pPass)
{
  if ((m_RP.m_nPassGroupID==EFSLIST_GENERAL || m_RP.m_nPassGroupID==EFSLIST_TRANSP) && !(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & (RBPF_SHADOWGEN|RBPF_ZPASS)))
  {
    // force per object fog      
    m_RP.m_FlagsShader_RT |= (g_HWSR_MaskBit[HWSR_FOG] | g_HWSR_MaskBit[HWSR_ALPHABLEND]);

    if ((pPass->m_RenderState & GS_DEPTHFUNC_MASK) == GS_DEPTHFUNC_LESS)
    {      
      if (!m_RP.m_bFirstPass)
      {
        nState = (nState & ~(GS_BLEND_MASK|GS_DEPTHFUNC_MASK|GS_DEPTHWRITE));
        if (pPass->m_RenderState & GS_DEPTHWRITE)
          nState |=GS_BLSRC_SRCALPHA| GS_BLDST_ONE | GS_DEPTHFUNC_EQUAL;
        else
          nState |= GS_BLSRC_SRCALPHA | GS_BLDST_ONE | GS_DEPTHFUNC_LEQUAL; //GS_BLSRC_ONESRCALPHA
      }
      else
      {
        nState = (nState & ~(GS_BLEND_MASK|GS_DEPTHFUNC_MASK));
        nState |= GS_DEPTHFUNC_LESS | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA; 

				if (pPass->m_RenderState & GS_DEPTHWRITE)
          nState |= GS_DEPTHWRITE;
        else
          nState &= ~GS_DEPTHWRITE;
      }
    }
    else
    {
      if (!m_RP.m_bFirstPass) 
      {
        nState = (nState & ~(GS_BLEND_MASK|GS_DEPTHFUNC_MASK|GS_DEPTHWRITE));
        nState |= GS_BLSRC_ONE| GS_BLDST_ONE | GS_DEPTHFUNC_EQUAL; 
      }
      else
      {
        nState = (nState & ~(GS_BLEND_MASK|GS_DEPTHFUNC_MASK));
        nState |= GS_DEPTHFUNC_EQUAL/*| GS_DEPTHWRITE*/;
      }
    }
  }
}

void CD3D9Renderer::FX_ScatterState(uint32& nState)
{
  m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_SCATTERSHADE ];
  if ((m_RP.m_FlagsPerFlush & RBSI_LOCKCULL) && (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_ZPASS)) //scattering z-only pass for proper skeleton visibility
  {
    nState &= ~GS_BLEND_MASK;
    nState |= GS_DEPTHWRITE;
    nState &= ~GS_NODEPTHTEST;
    nState |= GS_DEPTHFUNC_LEQUAL;

    nState &= ~GS_ALPHATEST_MASK;

    nState |= GS_COLMASK_NONE;
    //State |= GS_COLMASK_RGB;
  }
  else 
  if ((m_RP.m_FlagsPerFlush & RBSI_LOCKCULL) && (!m_RP.m_pShaderResources || !(m_RP.m_pShaderResources->m_ResFlags & MTL_FLAG_2SIDED))) //detect depth scattering case  
  {
    //depth estimation
    nState |= GS_NODEPTHTEST;
    //State |= GS_NODEPTHTEST;
    nState &= ~(GS_DEPTHWRITE | GS_ALPHATEST_MASK);
    //State &= ~GS_BLEND_MASK;
    nState |= (GS_BLSRC_ONE | GS_BLDST_ONE);






    nState |= GS_COLMASK_A;

    //State |= GS_COLMASK_RGB; //for silhouette
  }
  else 
  {

    //internal RGB skeleton and all occluders rendering
    //note: should be drawn before all the transparent parts
    nState &= ~GS_BLEND_MASK;
    if (!m_RP.m_bFirstPass)
    {
      nState |= GS_BLSRC_ONE | GS_BLDST_ONE;
    }
    nState |= GS_DEPTHWRITE;
    //enable depth test
    nState &= ~GS_NODEPTHTEST;
    //State |= GS_NODEPTHTEST;
    nState |= GS_DEPTHFUNC_LEQUAL;

    //TD:: skeleton front faces depth should be rendered and RGB skeleton should be rendered during next pass
    //for proper depth estimation 
    //State |= GS_COLMASK_A;
    //D3DSetCull(eCULL_Front);
    //m_RP.m_FlagsPerFlush |= RBSI_LOCKCULL;

    //State |= GS_COLMASK_NONE;
    //for RGB occluders rendering




    nState |= GS_COLMASK_RGB; 

  }
}

void CD3D9Renderer::FX_CommitStates(const SShaderTechnique *pTech, const SShaderPass *pPass, bool bUseMaterialState)
{
	FUNCTION_PROFILER_RENDER_FLAT
  uint32 State = 0;
  int AlphaRef = pPass->m_AlphaRef == 0xff ? -1 : pPass->m_AlphaRef;
  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];

  if (rRP.m_pCurObject->m_RState)
	{		
    switch (rRP.m_pCurObject->m_RState & OS_TRANSPARENT)
    {
      case OS_ALPHA_BLEND:
        State = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
        break;
      case OS_ADD_BLEND:
				State = GS_BLSRC_ONE | GS_BLDST_ONE;
        break;
      case OS_MULTIPLY_BLEND:
        State = GS_BLSRC_DSTCOL | GS_BLDST_SRCCOL;
        break;
    }
		
		State = ((rRP.m_pCurObject->m_RState & OS_TRANSPARENT) && (m_RP.m_PersFlags2 & RBPF2_THERMAL_RENDERMODE_PASS))? (GS_BLSRC_ONE | GS_BLDST_ONE) : State;

    if (rRP.m_pCurObject->m_RState & OS_NODEPTH_TEST)
      State |= GS_NODEPTHTEST;
    AlphaRef = 0;
  }
  else
    State = pPass->m_RenderState;    

  if (bUseMaterialState && rRP.m_MaterialStateOr != 0)
  {
    if (rRP.m_MaterialStateOr & GS_ALPHATEST_MASK)
      AlphaRef = rRP.m_MaterialAlphaRef;
    State &= ~rRP.m_MaterialStateAnd;
    State |=  rRP.m_MaterialStateOr;
  }

	//This has higher priority than material states as for alphatested material
	//it is forced to use depth writing (FX_SetResourcesState)
	if (rRP.m_pCurObject->m_RState & OS_TRANSPARENT)
		State &= ~GS_DEPTHWRITE;

  if (!(pTech->m_Flags & FHF_POSITION_INVARIANT) && !(pPass->m_PassFlags & SHPF_FORCEZFUNC))
    FX_ZState(State);
  if (bUseMaterialState && (rRP.m_pCurObject->m_fAlpha < 1.0f) && !rRP.m_bIgnoreObjectAlpha)
    State = (State & ~(GS_BLEND_MASK | GS_DEPTHWRITE)) | (GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA); 

	if (m_RP.m_PersFlags2 & RBPF2_THERMAL_RENDERMODE_TRANSPARENT_PASS)
	{
		State &= ~(GS_BLSRC_MASK | GS_BLDST_MASK);
		State |= GS_BLSRC_ONE | GS_BLDST_ONE;
	}

  State &= ~rRP.m_ForceStateAnd;
  State |=  rRP.m_ForceStateOr;

  //after the first pass we need to change the srcalpha-oneminusscralpha to scralpha-one
  if (!rRP.m_bFirstPass)
  {
    if ((State & GS_BLEND_MASK) == (GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA))
      State = (State & ~GS_BLEND_MASK) | GS_BLSRC_SRCALPHA | GS_BLDST_ONE;
		else if ((State & GS_BLEND_MASK) == (GS_BLSRC_SRCALPHA_A_ZERO | GS_BLDST_ONEMINUSSRCALPHA))
			State = (State & ~GS_BLEND_MASK) | GS_BLSRC_SRCALPHA_A_ZERO | GS_BLDST_ONE_A_ZERO;
    else
      State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONE | GS_BLDST_ONE;
  }

  if (rRP.m_pShader->m_Flags2 & EF2_HAIR)
    FX_HairState(State, pPass);
  
  if ((rRP.m_PersFlags2 & RBPF2_ALLOW_DEFERREDSHADING) && (rRP.m_pShader->m_Flags & EF_SUPPORTSDEFERREDSHADING))
  {
    if (rTI.m_PersFlags & RBPF_ZPASS)
    {    
      // Workaround for CAFE (GPU hangs and freezes on this)
//#ifndef CAFE
      if ((rRP.m_pShader->m_Flags & EF_DECAL) || rRP.m_nPassGroupID == EFSLIST_TERRAINLAYER)
      {
        State = (State & ~(GS_BLEND_MASK|GS_DEPTHWRITE|GS_DEPTHFUNC_MASK));
        State |= GS_DEPTHFUNC_LEQUAL | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;  
        rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_ALPHABLEND]; 
      }

      // Disable alpha writes - for alpha blend case we use default alpha value as a default power factor
      if (State & GS_BLEND_MASK)
        State |= GS_COLMASK_RGB;
//#endif
    }
  }

  //force no depth test for scattering passes
  if (SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID] == 1 && (rRP.m_nBatchFilter & FB_SCATTER))
    FX_ScatterState(State);

	if (rRP.m_PersFlags2 & RBPF2_CUSTOM_RENDER_PASS)
	{
		rRP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE0];
		if (CRenderer::CV_r_customvisions == 2)
		{
			rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
			State |= GS_BLSRC_ONE | GS_BLDST_ONE;
		}
	}

  if (m_NewViewport.fMaxZ <= 0.01f)
    State &= ~GS_DEPTHWRITE;

























  if (CV_r_VegetationAlphaTestOnly == 2)
    State &= ~GS_ALPHATEST_MASK;

	// Intermediate solution to disable depth testing in 3D HUD
	if (rRP.m_pCurObject->m_ObjFlags & FOB_RENDER_AFTER_POSTPROCESSING)
	{
	  State &= ~GS_DEPTHFUNC_MASK;
		State |= GS_NODEPTHTEST;
	}

  FX_SetState(State, AlphaRef);
  
  if (State & GS_ALPHATEST_MASK)
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_ALPHATEST];

  int nBlend;
  if (nBlend=(rRP.m_CurState & GS_BLEND_MASK))
  {
    if (nBlend == (GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA)
			|| nBlend == (GS_BLSRC_SRCALPHA | GS_BLDST_ONE)
			|| nBlend == (GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA)
			|| nBlend == (GS_BLSRC_SRCALPHA_A_ZERO | GS_BLDST_ONEMINUSSRCALPHA))
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_ALPHABLEND];
  }
}

//=====================================================================================























void CD3D9Renderer::FX_GetRTDimensions(bool bRTPredicated, int& nWidth, int& nHeight, bool bForcePredicated)
{




































}

bool CD3D9Renderer::FX_GetTargetSurfaces(CTexture *pTarget, D3DSurface*& pTargSurf, SRTStack *pCur, int nCMSide, int nTarget, bool bFP16, uint32 nTileCount)
{
  if (pTarget)
  {
    if (!CTexture::IsTextureExist(pTarget) && !pTarget->m_bNoDevTexture)
      pTarget->CreateRenderTarget(eTF_Unknown);









































































    
		if (!CTexture::IsTextureExist(pTarget))
      return false;
#if defined (DIRECT3D9)
    pTargSurf = (D3DSurface *)pTarget->GetDeviceRT();
    if (pTargSurf)
      pTargSurf->AddRef();
    else
      pTargSurf = pTarget->GetSurface(nCMSide, 0);
#elif defined (DIRECT3D10)
    pTargSurf = pTarget->GetSurface(nCMSide, 0);
#endif


  }
  else
    pTargSurf = NULL;
  return true;
}

bool CD3D9Renderer::FX_SetRenderTarget(int nTarget, D3DSurface *pTargetSurf, SD3DSurface *pDepthTarget, bool bClearOnResolve, uint32 nTileCount)
{
	if (nTarget >= RT_STACK_WIDTH || m_nRTStackLevel[nTarget] >= MAX_RT_STACK)
		return false;
  HRESULT hr = 0;
  SRTStack *pCur = &m_RTStack[nTarget][m_nRTStackLevel[nTarget]];
  pCur->m_pTarget = pTargetSurf;
  pCur->m_pSurfDepth = pDepthTarget;
  pCur->m_pDepth = pDepthTarget ? (D3DDepthSurface *)pDepthTarget->pSurf : NULL;
  pCur->m_pTex = NULL;

#ifdef _DEBUG
  if (m_nRTStackLevel[nTarget] == 0 && nTarget == 0)
  {
    assert(pCur->m_pTarget == m_pBackBuffer && pCur->m_pDepth == m_pZBuffer);
  }
#endif

  pCur->m_bNeedReleaseRT = false;
  pCur->m_bWasSetRT = false;
  pCur->m_bWasSetD = false;
	pCur->m_bResetViewportForClear = false;
  pCur->m_bClearOnResolve = bClearOnResolve;
  pCur->m_ClearFlags = 0;
  m_pNewTarget[nTarget] = pCur;
  if (nTarget == 0)
  {
    m_RP.m_StateOr &= ~GS_COLMASK_NONE;
  }
  m_nMaxRT2Commit = max(m_nMaxRT2Commit, nTarget);







  return (hr == S_OK);
}
bool CD3D9Renderer::FX_PushRenderTarget(int nTarget, D3DSurface *pTargetSurf, SD3DSurface *pDepthTarget, bool bClearOnResolve, uint32 nTileCount)
{
	assert(m_pRT->IsRenderThread());
	if (nTarget >= RT_STACK_WIDTH || m_nRTStackLevel[nTarget] >= MAX_RT_STACK)
		return false;
  m_nRTStackLevel[nTarget]++;	
  return FX_SetRenderTarget(nTarget, pTargetSurf, pDepthTarget, bClearOnResolve, nTileCount);
}

bool CD3D9Renderer::FX_SetRenderTarget(int nTarget, CTexture *pTarget, SD3DSurface *pDepthTarget, bool bPush, bool bClearOnResolve, int nCMSide, bool bScreenVP, uint32 nTileCount)
{
  assert(!nTarget || !pDepthTarget);
	assert((unsigned int) nTarget < RT_STACK_WIDTH);

	if(pTarget && !(pTarget->GetFlags() & FT_USAGE_RENDERTARGET))
	{
		CryFatalError( "Attempt to bind a non-render-target texture as a render-target" );
	}

  if (pTarget && pDepthTarget)
  {
#ifndef XENON
    if (pTarget->GetWidth() > pDepthTarget->nWidth || pTarget->GetHeight() > pDepthTarget->nHeight)
    {
      iLog->LogError("Error: RenderTarget '%s' size:%i x %i DepthSurface size:%i x %i \n", pTarget->GetName(), pTarget->GetWidth(), pTarget->GetHeight(), pDepthTarget->nWidth, pDepthTarget->nHeight);
    }
    assert(pTarget->GetWidth() <= pDepthTarget->nWidth);
    assert(pTarget->GetHeight() <= pDepthTarget->nHeight);
#endif
  }

	if (nTarget >= RT_STACK_WIDTH || m_nRTStackLevel[nTarget] >= MAX_RT_STACK)
		return false;

  SRTStack *pCur = &m_RTStack[nTarget][m_nRTStackLevel[nTarget]];
  D3DSurface* pTargSurf;
  bool bFP16 = false;
  if (pCur->m_pTex)
  {
    bFP16 = pCur->m_pTex->IsHighQualityFiltered();
    if (pCur->m_bNeedReleaseRT)
    {
      pCur->m_bNeedReleaseRT = false;




    }
    if (pCur->m_pTarget && pCur->m_pTarget == m_pNewTarget[0]->m_pTarget)
    {



    }
    m_pNewTarget[0]->m_bWasSetRT = false;
#if defined (DIRECT3D9)
    SAFE_RELEASE(pCur->m_pTarget);
#endif
    m_pNewTarget[0]->m_pTarget = NULL;

    pCur->m_pTex->Unlock();
  }

#if defined (DIRECT3D10)
  if (!pTarget)
    pTargSurf = NULL;
  else
  {
    if (!FX_GetTargetSurfaces(pTarget, pTargSurf, pCur, nCMSide, nTarget, bFP16, nTileCount))
      return false;
  }
#else
  if (!pTarget)
    return false;
  if (!FX_GetTargetSurfaces(pTarget, pTargSurf, pCur, nCMSide, nTarget, bFP16, nTileCount))
    return false;
#endif

  if (pTarget)
  {
    int nFrameID = m_RP.m_TI[m_RP.m_nProcessThreadID].m_nFrameUpdateID;
    if (pTarget && pTarget->m_nUpdateFrameID != nFrameID)
    {
      pTarget->m_nUpdateFrameID = nFrameID;
    }
  }

  if (!bPush && pDepthTarget && pDepthTarget->pSurf != pCur->m_pDepth)
  {
    //assert(pCur->m_pDepth == m_pCurDepth);
    //assert(pCur->m_pDepth != m_pZBuffer);   // Attempt to override default Z-buffer surface
    if (pCur->m_pSurfDepth)
      pCur->m_pSurfDepth->bBusy = false;
  }
  pCur->m_pDepth = pDepthTarget ? (D3DDepthSurface *)pDepthTarget->pSurf : NULL;
  pCur->m_ClearFlags = 0;
  pCur->m_pTarget = pTargSurf;
  pCur->m_bNeedReleaseRT = true;
  pCur->m_bWasSetRT = false;
  pCur->m_bWasSetD = false;
  pCur->m_bScreenVP = bScreenVP;
  pCur->m_bClearOnResolve = bClearOnResolve;
	pCur->m_bResetViewportForClear = false;



  if (pTarget)
    pTarget->Lock();
  if (pDepthTarget)
  {
    pDepthTarget->bBusy = true;
    pDepthTarget->nFrameAccess = m_RP.m_TI[m_RP.m_nProcessThreadID].m_nFrameUpdateID;
  }

  if (pTarget)
    pCur->m_pTex = pTarget;
  else if(pDepthTarget)
		pCur->m_pTex = (CTexture*)pDepthTarget->pTex;
	else
		pCur->m_pTex = NULL;

  pCur->m_pSurfDepth = pDepthTarget;

  if (pTarget)
  {
    pCur->m_Width = pTarget->GetWidth();
    pCur->m_Height = pTarget->GetHeight();
  }
  else 
  if (pDepthTarget)
  {
    pCur->m_Width = pDepthTarget->nWidth;
    pCur->m_Height = pDepthTarget->nHeight;
  }
  if (!nTarget)
  {
#if defined (DIRECT3D9)
    m_CurViewport.nWidth = pCur->m_Width;
    m_CurViewport.nHeight = pCur->m_Height;
#endif
    if (bScreenVP)
      RT_SetViewport(m_MainViewport.nX, m_MainViewport.nY, m_MainViewport.nWidth, m_MainViewport.nHeight);
    else
      RT_SetViewport(0, 0, pCur->m_Width, pCur->m_Height);
  }
  m_pNewTarget[nTarget] = pCur;
  m_nMaxRT2Commit = max(m_nMaxRT2Commit, nTarget);    

  return true;
}
bool CD3D9Renderer::FX_PushRenderTarget(int nTarget, CTexture *pTarget, SD3DSurface *pDepthTarget, bool bClearOnResolve, int nCMSide, bool bScreenVP, uint32 nTileCount)
{
	assert(m_pRT->IsRenderThread());
	if (nTarget >= RT_STACK_WIDTH || m_nRTStackLevel[nTarget] == MAX_RT_STACK)
	{
		assert(0);
		return false;
	}
  m_nRTStackLevel[nTarget]++;
  return FX_SetRenderTarget(nTarget, pTarget, pDepthTarget, true, bClearOnResolve, nCMSide, bScreenVP, nTileCount);
}

bool CD3D9Renderer::FX_RestoreRenderTarget(int nTarget)
{
	if (nTarget >= RT_STACK_WIDTH || m_nRTStackLevel[nTarget] < 0)
		return false;

  SRTStack *pCur = &m_RTStack[nTarget][m_nRTStackLevel[nTarget]];
#ifdef _DEBUG
  if (m_nRTStackLevel[nTarget] == 0 && nTarget == 0)
  {
    assert(pCur->m_pTarget == m_pBackBuffer && pCur->m_pDepth == m_pZBuffer);
  }
#endif

  SRTStack *pPrev = &m_RTStack[nTarget][m_nRTStackLevel[nTarget]+1];
  if (pPrev->m_bNeedReleaseRT)
  {
    pPrev->m_bNeedReleaseRT = false;




    if (pPrev->m_pTarget && pPrev->m_pTarget == m_pNewTarget[nTarget]->m_pTarget)
    {
      m_pNewTarget[nTarget]->m_bWasSetRT = false;


#if defined(DIRECT3D9)
      if( nTarget )
        m_pd3dDevice->SetRenderTarget(nTarget, NULL);
#endif

#if defined (DIRECT3D9)
      pPrev->m_pTarget->Release();
#endif
      pPrev->m_pTarget = NULL;
      m_pNewTarget[nTarget]->m_pTarget = NULL;
    }
  }

  if (nTarget == 0)
  {
    if (pPrev->m_pSurfDepth)
    {
      pPrev->m_pSurfDepth->bBusy = false;
      pPrev->m_pSurfDepth = NULL;
    }
  }
  if (pPrev->m_pTex)
  {
    pPrev->m_pTex->Unlock();
    pPrev->m_pTex = NULL;
  }
  if (!nTarget)
  {
#if defined (DIRECT3D9)
    m_CurViewport.nWidth = pCur->m_Width;
    m_CurViewport.nHeight = pCur->m_Height;
#endif
    if (pCur->m_bScreenVP)
      RT_SetViewport(m_MainViewport.nX, m_MainViewport.nY, m_MainViewport.nWidth, m_MainViewport.nHeight);
    else
    if (!m_nRTStackLevel[nTarget])
      RT_SetViewport(0, 0, GetWidth(), GetHeight());
    else
      RT_SetViewport(0, 0, pCur->m_Width, pCur->m_Height);
  }
  pCur->m_bWasSetD = false;
  pCur->m_bWasSetRT = false;
  m_pNewTarget[nTarget] = pCur;
  m_nMaxRT2Commit = max(m_nMaxRT2Commit, nTarget );
  



  return true;
}
bool CD3D9Renderer::FX_PopRenderTarget(int nTarget)
{
  assert(m_pRT->IsRenderThread());
  if (m_nRTStackLevel[nTarget] <= 0)
  {
    assert(0);
    return false;
  }
  m_nRTStackLevel[nTarget]--;
  return FX_RestoreRenderTarget(nTarget);
}

//XENON version















































































     
SD3DSurface *CD3D9Renderer::FX_GetDepthSurface(int nWidth, int nHeight, bool bAA)
{
  assert(m_pRT->IsRenderThread());

  SD3DSurface *pSrf = NULL;
  uint32 i;
  int nBestX = -1;
  int nBestY = -1;
  for (i=0; i<m_TempDepths.Num(); i++)
  {
    pSrf = m_TempDepths[i];
    if (!pSrf->bBusy)
    {
      if (pSrf->nWidth == nWidth && pSrf->nHeight == nHeight)
      {
        nBestX = i;
        break;
      }
      if (nBestX < 0 && pSrf->nWidth == nWidth && pSrf->nHeight >= nHeight)
        nBestX = i;
      else
        if (nBestY < 0 && pSrf->nWidth >= nWidth && pSrf->nHeight == nHeight)
          nBestY = i;
    }
  }
  if (nBestX >= 0)
    return m_TempDepths[nBestX];
  if (nBestY >= 0)
    return m_TempDepths[nBestY];

	
	bool allowUsingLargerRT = true;



#if defined(DIRECT3D10)	
	if( CV_d3d10_debugruntime )
		allowUsingLargerRT = false;
#endif

	if( allowUsingLargerRT )
	{
		for (i=0; i<m_TempDepths.Num(); i++)
		{
			pSrf = m_TempDepths[i];
			if (pSrf->nWidth >= nWidth && pSrf->nHeight >= nHeight && !pSrf->bBusy)
				break;
		}
	}
	else
	{
		i = m_TempDepths.Num();
	}

  if (i == m_TempDepths.Num())
  {
		ScopedSwitchToGlobalHeap useGlobalHeap;
    pSrf = new SD3DSurface;
    pSrf->nWidth = nWidth;
    pSrf->nHeight = nHeight;
    pSrf->nFrameAccess = -1;
    pSrf->bBusy = false;



















#if defined (DIRECT3D9)
    m_pd3dDevice->CreateDepthStencilSurface(nWidth, nHeight, m_ZFormat, D3DMULTISAMPLE_NONE, 0, FALSE, (LPDIRECT3DSURFACE9 *)(&pSrf->pSurf), NULL);
#elif defined (DIRECT3D10)
    HRESULT hr;
    D3D11_TEXTURE2D_DESC descDepth;
    ZeroStruct(descDepth);
    descDepth.Width = nWidth;
    descDepth.Height = nHeight;
    descDepth.MipLevels = 1;
    descDepth.ArraySize = 1;
    descDepth.Format = m_ZFormat;
    descDepth.SampleDesc.Count = 1;
    descDepth.SampleDesc.Quality = 0;
    descDepth.Usage = D3D11_USAGE_DEFAULT;
    descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    descDepth.CPUAccessFlags = 0;
    descDepth.MiscFlags = 0;
		
    hr = m_pd3dDevice->CreateTexture2D(&descDepth,       // Texture desc
      NULL,                  // Initial data
      alias_cast<ID3D11Texture2D**>(&pSrf->pTex) ); // [out] Texture
    assert(hr == S_OK);
		if(hr == S_OK)
		{
			D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
			ZeroStruct(descDSV);
			descDSV.Format = m_ZFormat;
			descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
			descDSV.Texture2D.MipSlice = 0;
			// Create the depth stencil view			
			hr = m_pd3dDevice->CreateDepthStencilView((ID3D11Texture2D *)pSrf->pTex, // Depth stencil texture
				&descDSV, // Depth stencil desc
				alias_cast<ID3D11DepthStencilView**>(&pSrf->pSurf) );  // [out] Depth stencil view
			if(hr != S_OK)
			{
				//free u.ppTex2D
				((ID3D11Texture2D *)(pSrf->pTex))->Release();
				SAFE_DELETE(pSrf);
				return NULL;
			}
		}
		else
		{
			SAFE_DELETE(pSrf);
			return NULL;
		}
#endif
		m_TempDepths.AddElem(pSrf);
  }

  return pSrf;
}



SD3DSurface *CD3D9Renderer::FX_GetScreenDepthSurface(bool bAA)
{
  SD3DSurface *pSurf = FX_GetDepthSurface(m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, bAA);
  assert(pSurf);
  return pSurf;
}


void *CD3D9Renderer::FX_LockVB(uint32 nSize, uint32& nStart, bool bNonStalling)
{
  void* pVB = NULL;

  DynamicVB<byte>* pDynVB = m_RP.m_pVBs;
  assert(pDynVB);
  if (pDynVB)
    pVB = (void *)pDynVB->LockVB(nSize, nStart, bNonStalling);

  return pVB;
}
void CD3D9Renderer::FX_UnlockVB()
{
  m_RP.m_pVBs->UnlockVB();
}

// Commit changed states to the hardware before drawing
bool CD3D9Renderer::FX_CommitStreams(SShaderPass *sl, bool bSetVertexDecl)
{
	FUNCTION_PROFILER_RENDER_FLAT

  //PROFILE_FRAME(Draw_Predraw);
  SRenderPipeline& RESTRICT_REFERENCE rp(m_RP);

#ifdef TESSELLATION_RENDERER
  if (CHWShader_D3D::m_pCurInstHS)
  {
    rp.m_FlagsStreams_Stream |= (1<<VSF_NORMALS);
    rp.m_FlagsStreams_Decl |= (1<<VSF_NORMALS);
  }
#endif

  HRESULT hr;	
  if (bSetVertexDecl)
  {
    hr = FX_SetVertexDeclaration(rp.m_FlagsStreams_Decl, rp.m_CurVFormat);
    if (FAILED(hr))
      return false;
  }

  if (rp.m_pRE)
	{
		 bool bRet = rp.m_pRE->mfPreDraw(sl);
		 return bRet;
	}
	else if (rp.m_RendNumVerts && rp.m_RendNumIndices)
  {		
		if( rp.m_FlagsPerFlush & RBSI_EXTERN_VMEM_BUFFERS )
		{			
			assert(rp.m_pExternalVertexBuffer);
			assert(rp.m_pExternalIndexBuffer);

			// bind out external vertex/index buffer to use those directly, the client code has to set them up correctly
			rp.m_pExternalVertexBuffer->Bind(0, 0, rp.m_StreamStride);
			rp.m_pExternalIndexBuffer->Bind();

			// adjust the first index to render from as well as 
			// other renderer stats
			rp.m_nStreamOffset[0] = 0;
			rp.m_FirstIndex = rp.m_nExternalVertexBufferFirstIndex;	
			rp.m_FirstVertex = rp.m_nExternalVertexBufferFirstVertex;	

			rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_StreamStride*rp.m_RendNumVerts;
			rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_RendNumIndices*sizeof(short);

			// clear external video memory buffer flag
			rp.m_FlagsPerFlush &= ~RBSI_EXTERN_VMEM_BUFFERS;
			rp.m_nExternalVertexBufferFirstIndex = 0;
			rp.m_nExternalVertexBufferFirstVertex = 0;
			rp.m_pExternalVertexBuffer = NULL;
			rp.m_pExternalIndexBuffer = NULL;
		}
    else 
		{
			if (!(rp.m_FlagsPerFlush & RBSI_VERTSMERGED))
			{
				uint32 nStart;
				uint32 nSize = rp.m_StreamStride*rp.m_RendNumVerts;
				rp.m_FlagsPerFlush |= RBSI_VERTSMERGED;

				void *pVB = FX_LockVB(nSize, nStart);
				assert(pVB);
#if defined(DIRECT3D9) && (defined(WIN32) || defined(WIN64))
				if (!pVB)
					return false;
#endif

#ifndef XENON
				memcpy(pVB, rp.m_StreamPtr.Ptr, nSize);


#endif
				FX_UnlockVB();
				rp.m_FirstVertex = 0;
				rp.m_nStreamOffset[0] = nStart;
				rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += nSize;

				uint16 *pIB = rp.m_pIndexBuf->LockIB(rp.m_RendNumIndices, nStart);
				if (!pIB)
					return false;

#ifndef XENON
				memcpy(pIB, rp.m_SysRendIndices, rp.m_RendNumIndices * sizeof(short));


#endif
				rp.m_pIndexBuf->UnlockIB();
				rp.m_FirstIndex = nStart;
				rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_RendNumIndices*sizeof(short);
			}
			rp.m_pIndexBuf->Bind();

			if (rp.m_FlagsStreams_Stream & VSM_TANGENTS)
			{
				if (!(rp.m_FlagsPerFlush & RBSI_TANGSMERGED))
				{
					uint32 nStart;
					uint32 nSize = sizeof(SPipTangents)*rp.m_RendNumVerts;
					rp.m_FlagsPerFlush |= RBSI_TANGSMERGED;

					void *pVB = FX_LockVB(nSize, nStart);
					assert(pVB);
#if defined(DIRECT3D9) && (defined(WIN32) || defined(WIN64))
					if (!pVB)
						return false;
#endif

					memcpy(pVB, rp.m_StreamPtrTang.Ptr, nSize);
					FX_UnlockVB();
					rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += nSize;
					rp.m_nStreamOffset[VSF_TANGENTS] = nStart;
				}
				rp.m_pVBs->Bind(VSF_TANGENTS, rp.m_nStreamOffset[VSF_TANGENTS], sizeof(SPipTangents));
				rp.m_PersFlags1 |= RBPF1_USESTREAM<<VSF_TANGENTS;
			}
			else 
			if (rp.m_PersFlags1 & (RBPF1_USESTREAM<<(VSF_TANGENTS | VSF_QTANGENTS)))
			{
				rp.m_PersFlags1 &= ~(RBPF1_USESTREAM<<(VSF_TANGENTS | VSF_QTANGENTS));
				FX_SetVStream(1, NULL, 0, 0);
			}
			rp.m_pVBs->Bind(0, rp.m_nStreamOffset[0], rp.m_StreamStride);
		}
  }

  return true;
}


#ifdef CD3D9RENDERER_DEBUG_CONSISTENCY_CHECK 
bool CD3D9Renderer::FX_DebugCheckConsistency(int FirstVertex, int FirstIndex, int RendNumVerts, int RendNumIndices)
{
  if (CV_r_validateDraw != 2)
    return true;
  HRESULT hr = S_OK;
  assert(m_RP.m_VertexStreams[0].pStream);
  //assert(m_RP.m_VertexStreams[0].nFreq == 1);
  D3DVertexBuffer *pVB = (D3DVertexBuffer *)m_RP.m_VertexStreams[0].pStream;
  D3DIndexBuffer *pIB = (D3DIndexBuffer *)m_RP.m_pIndexStream;
  assert(pIB && pVB);
  if (!pIB || !pVB)
    return false;
  int i;
  int nVBOffset = m_RP.m_VertexStreams[0].nOffset;

  uint16 *pIBData = (uint16 *)m_DevBufMan.LockIB(pIB, FirstIndex, FSL_READ);
  byte *pVBData = (byte *)m_DevBufMan.LockVB(pVB, nVBOffset, FSL_READ);
  EVertexFormat eVBFormat = m_RP.m_CurVFormat;
  int nVBStride = CRenderMesh::m_cSizeVF[eVBFormat];
  SOnDemandD3DVertexDeclarationCache *pDecl = &m_RP.m_D3DVertexDeclarationCache[(m_RP.m_FlagsStreams_Decl&0xff)>>1][eVBFormat][0];
  assert(pDecl->m_pDeclaration);

  Vec3 vMax, vMin;
  vMin = Vec3(100000.0f, 100000.0f, 100000.0f);
  vMax = Vec3(-100000.0f, -100000.0f, -100000.0f);

  for (i=0; i<RendNumIndices; i++)
  {
    int nInd = pIBData[i];
    assert(nInd>=FirstVertex && nInd<FirstVertex+RendNumVerts);
    byte *pV = &pVBData[nInd*nVBStride];
    Vec3 VV = ((Vec3f16 *)pV)->ToVec3();
    vMin.CheckMin(VV);
    vMax.CheckMax(VV);
    Vec3 vAbs = VV.abs();
    assert(vAbs.x < 10000.0f && vAbs.y < 10000.0f && vAbs.z < 10000.0f);
    if(vAbs.x > 10000.0f || vAbs.y > 10000.0f || vAbs.z > 10000.0f || !_finite(vAbs.x) || !_finite(vAbs.y) || !_finite(vAbs.z))
      hr = S_FALSE;
  }
  Vec3 vDif = vMax - vMin;
  assert(vDif.x < 10000.0f && vDif.y < 10000.0f && vDif.z < 10000.0f);
  if (vDif.x >= 10000.0f || vDif.y > 10000.0f || vDif.z > 10000.0f)
    hr = S_FALSE;

  m_DevBufMan.UnlockIB(pIB);
  m_DevBufMan.UnlockVB(pVB);
  if (hr != S_OK)
  {
    iLog->LogError("ERROR: CD3D9Renderer::FX_DebugCheckConsistency: Validation failed for DIP (Shader: '%s')\n", m_RP.m_pShader->GetName());
  }
  return (hr==S_OK);
}
#endif

// Draw current indexed mesh
void CD3D9Renderer::FX_DrawIndexedMesh (const eRenderPrimitiveType nPrimType)
{
	FUNCTION_PROFILER_RENDER_FLAT

	FX_Commit();

#if defined (DIRECT3D10)
	// Don't render fallback in DX11
	if (!CHWShader_D3D::m_pCurInstVS || !CHWShader_D3D::m_pCurInstPS || CHWShader_D3D::m_pCurInstVS->m_bFallback || CHWShader_D3D::m_pCurInstPS->m_bFallback)
		return;
	if (CHWShader_D3D::m_pCurInstGS && CHWShader_D3D::m_pCurInstGS->m_bFallback)
		return;
	static const int nFirstVertex = 0;		// AntonK: on DX11/PS3 this index is already taken into account in a different place in pipeline
#else
	const int nFirstVertex = m_RP.m_FirstVertex;
#endif

	PROFILE_FRAME(Draw_DrawCall);

	if (nPrimType != eptHWSkinGroups)
	{
		FX_DebugCheckConsistency(m_RP.m_FirstVertex, m_RP.m_FirstIndex+m_RP.m_IndexOffset, m_RP.m_RendNumVerts, m_RP.m_RendNumIndices);
		eRenderPrimitiveType eType = nPrimType;
		int nFirstI = m_RP.m_FirstIndex;
		int nNumI = m_RP.m_RendNumIndices;
#ifdef TESSELLATION_RENDERER
		if (CHWShader_D3D::m_pCurInstHS)
		{
			FX_SetAdjacencyOffsetBuffer();
			eType = ept3ControlPointPatchList;
		}
#endif
		FX_DrawIndexedPrimitive(eType, 0, nFirstVertex, m_RP.m_RendNumVerts, nFirstI+m_RP.m_IndexOffset, nNumI);

#if defined(ENABLE_PROFILING_CODE)
#	ifdef TESSELLATION_RENDERER
			m_RP.m_PS[m_RP.m_nProcessThreadID].m_nPolygonsByTypes[m_RP.m_nPassGroupDIP][(m_RP.m_FlagsShader_RT&g_HWSR_MaskBit[HWSR_VEGETATION])?EVCT_VEGETATION: EVCT_STATIC][m_RP.m_nBatchFilter == FB_Z] += (nPrimType == eptTriangleList || nPrimType == ept3ControlPointPatchList ? nNumI/3 : nNumI-2);
#	else
			m_RP.m_PS[m_RP.m_nProcessThreadID].m_nPolygonsByTypes[m_RP.m_nPassGroupDIP][(m_RP.m_FlagsShader_RT&g_HWSR_MaskBit[HWSR_VEGETATION])?EVCT_VEGETATION: EVCT_STATIC][m_RP.m_nBatchFilter == FB_Z] += (nPrimType == eptTriangleList ? nNumI/3 : nNumI-2);
#	endif
#endif
	}
	else
	{
		CRenderChunk *pChunk = m_RP.m_pRE->mfGetMatInfo();
		if (pChunk)   
		{
			eRenderPrimitiveType eType = eptTriangleList;
			// SHWSkinBatch *pBatch = pChunk->m_pHWSkinBatch;
			FX_DebugCheckConsistency(m_RP.m_FirstVertex, pChunk->nFirstIndexId+m_RP.m_IndexOffset, pChunk->nNumVerts, pChunk->nNumIndices);

		#ifdef TESSELLATION_RENDERER
			if (CHWShader_D3D::m_pCurInstHS)
			{
				// try to stitch the seams
				FX_SetAdjacencyOffsetBuffer();
				eType = ept3ControlPointPatchList;
			}
		#endif
			FX_DrawIndexedPrimitive(eType, 0, nFirstVertex, pChunk->nNumVerts, pChunk->nFirstIndexId+m_RP.m_IndexOffset, pChunk->nNumIndices);

		#if defined(ENABLE_PROFILING_CODE)
			m_RP.m_PS[m_RP.m_nProcessThreadID].m_nPolygonsByTypes[m_RP.m_nPassGroupDIP][EVCT_SKINNED][m_RP.m_nBatchFilter == FB_Z] += (pChunk->nNumIndices / 3);
		#endif
		}
	}
}


//====================================================================================

struct SShadowLight
{
  PodArray<ShadowMapFrustum*> *pSmLI;
  SRenderLight *pDL;
};

static bool sbHasDot3LM;
static _inline int Compare(SShadowLight &a, SShadowLight &b)
{
  if (a.pSmLI->Count() > b.pSmLI->Count())
    return -1;
  if (a.pSmLI->Count() < b.pSmLI->Count())
    return 1;
  if (sbHasDot3LM)
  {
    if ((a.pDL->m_Flags & DLF_LM) < (b.pDL->m_Flags & DLF_LM))
      return -1;
    if ((a.pDL->m_Flags & DLF_LM) > (b.pDL->m_Flags & DLF_LM))
      return -1;
  }
  return 0;
}

static inline void sFillLP(SLightPass *pLP, uint32& i, SRenderLight** pLight, int nLights, const int nMaxLights, bool& bHasAmb)
{
  if (!nLights || !nMaxLights)
    return;
  int j, n, m;
  int nActualMaxLights = nMaxLights;
  bHasAmb = false;
  m = 0;

  for (j=0; j<32; j++)
  {
    nActualMaxLights = (nLights < nActualMaxLights) ? nLights : nActualMaxLights;
    if (!nActualMaxLights)
      break;
    for (n=0; n<nActualMaxLights; n++)
    {
      pLP[i].pLights[n] = pLight[m++];
    }
    pLP[i].nLights = n;
    i++;
    nLights -= n;
    nActualMaxLights = nMaxLights;
  }
}

void CD3D9Renderer::FX_StencilLights(SLightPass *pLP)
{
  if (SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID] > 1)
    return;
  if (!pLP->nLights || (m_RP.m_FlagsShader_RT & g_HWSR_MaskBit[HWSR_AMBIENT]))
  {
    FX_SetStencilState(
      STENC_FUNC(FSS_STENCFUNC_ALWAYS) |
      STENCOP_FAIL(FSS_STENCOP_KEEP) |
      STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
      STENCOP_PASS(FSS_STENCOP_KEEP),
      0x0, 0xF/*pLP->nStencLTMask*/, 0xFFFFFFFF
      );
  }
  else
  {

    //FX_StencilRefresh(STENC_FUNC(FSS_STENCFUNC_NOTEQUAL), 0x0, pLP->nStencLTMask);
    //uint32 nStencilMask = 1<<(nLod - 1);
    FX_SetStencilState(
      STENC_FUNC(FSS_STENCFUNC_NOTEQUAL) |
      STENCOP_FAIL(FSS_STENCOP_KEEP) |
      STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
      STENCOP_PASS(FSS_STENCOP_KEEP),
      0x0, 0xF/*pLP->nStencLTMask*/, 0xFFFFFFFF
    );
  }
  return;
}

int CD3D9Renderer::FX_SetupLightPasses(SShaderTechnique *pTech)
{
	FUNCTION_PROFILER_RENDER_FLAT
  uint32 i;
  if (!pTech->m_Passes.Num())
    return -1;
  if (pTech->m_Flags & FHF_NOLIGHTS)
  {
    if (m_RP.m_pSunLight && (m_RP.m_DynLMask & 1))
    {
      m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_AMBIENT];
      if (m_bTerrainAOEnabled && pTech->m_Flags & FHF_TERRAIN)
        m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_AMBIENT_OCCLUSION];
    }
    m_RP.m_LPasses[0].nLights = 0;
    m_RP.m_LPasses[0].nLTMask = 0;
    m_RP.m_nNumLightPasses = 1;
    m_RP.m_PrevLMask = 0;
    return 1;
  }
  int nLightGroup = (m_RP.m_nBatchFilter & (FB_Z)) ? 0 : m_RP.m_nCurLightGroup;
  uint32 nAffectMask = nLightGroup < 0 ? -1 : (0xf << (nLightGroup*4));
  uint32 nMask = m_RP.m_DynLMask & nAffectMask;
  //uint32 nStencGroupLTMask = (nMask >> (nLightGroup*4)) & 0xf;

  bool bHasAmb = m_RP.m_bFirstPass;
  if (m_RP.m_nNumRendPasses > 0)
    bHasAmb = false;
  if (bHasAmb)
    m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_AMBIENT];

  if (nMask == m_RP.m_PrevLMask && CV_r_optimisedlightsetup)
    return m_RP.m_nNumLightPasses;
  m_RP.m_PrevLMask = nMask;

#ifndef _RELEASE
  m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumLightSetups++;
#endif

  int nDirLights = 0;
  int nOmniLights = 0;
  int nProjLights = 0;
  SRenderLight *DirLights[4];
  SRenderLight *OmniLights[32];
  SRenderLight *ProjLights[32];
	bool bPost3DRendererPass = (m_RP.m_PersFlags2 & RBPF2_POST_3D_RENDERER_PASS) ? true : false;
  if (nMask || bPost3DRendererPass)
  {
    uint32 nFirst = nLightGroup < 0 ? 0 : nLightGroup*4;
    SShaderPass *slw = &pTech->m_Passes[0];
    int nR = SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID]-1;
#ifndef _RELEASE
  if (nR<0) __debugbreak();
#endif 
    uint32 nLight;
    CRenderObject *pObj = m_RP.m_pCurObject;

    SRenderLight *dl;
    for (nLight=nFirst; nLight<m_RP.m_DLights[m_RP.m_nProcessThreadID][nR].Num(); nLight++)
    {
			if ((nMask & (1<<nLight)) || bPost3DRendererPass)
			{
				dl = &m_RP.m_DLights[m_RP.m_nProcessThreadID][nR][nLight];

				bool bPost3DRendererLight = (dl->m_Flags & DLF_POST_3D_RENDERER) ? true : false;

				if(bPost3DRendererLight == bPost3DRendererPass) // Avoid "post 3d renderer" lights in non-"post 3d renderer" pass, and vise versa
				{
					if ((dl->m_Flags & DLF_DIRECTIONAL) && (CV_r_optimisedlightsetup==2 || CV_r_optimisedlightsetup==3))
						DirLights[nDirLights++] = dl;
					else
						if (dl->m_Flags & DLF_PROJECT)
							ProjLights[nProjLights++] = dl;
						else
							OmniLights[nOmniLights++] = dl;
					if (nLightGroup >= 0)
					{
						//dl->m_ShadowChanMask = Vec4(0,0,0,0);
						//assert(nLight-nFirst <= 3);
						//dl->m_ShadowChanMask[nLight-nFirst] = 1;

						// Set shadow mask channel (R-G-B-A)
						dl->m_ShadowChanMask = 0;
						assert(nLight-nFirst <= 3);
						dl->m_ShadowChanMask |= (1<<(nLight-nFirst));
					}
				}
			}
    }
  }
  if (!bHasAmb && !nDirLights && !nOmniLights && !nProjLights)
  {
    m_RP.m_nNumLightPasses = -1;
    return -1;
  }
  i = 0;
  if (nMask || bPost3DRendererPass)
  {
#if !defined (XENON) && !defined(PS3)
    uint32 nMaxLights = 4;
    if (CV_r_lightssinglepass || (m_RP.m_pShader && (m_RP.m_pShader->m_Flags2 & EF2_SINGLELIGHTPASS)))
      nMaxLights = 1;


#endif
    sFillLP(&m_RP.m_LPasses[0], i, DirLights,  nDirLights,  nMaxLights, bHasAmb);
    sFillLP(&m_RP.m_LPasses[0], i, OmniLights, nOmniLights, nMaxLights, bHasAmb);
    sFillLP(&m_RP.m_LPasses[0], i, ProjLights, nProjLights, min(nMaxLights,1U), bHasAmb);
  }

  //no lightpass for ambient light, we need to create one
  if (bHasAmb)
  {
    m_RP.m_LPasses[0].nLights = 0;
    m_RP.m_LPasses[0].nLTMask = 0;
    m_RP.m_nNumLightPasses = 1;
    return 1;
  }

  int numPasses = i;
  int nPass;
  for (nPass=0; nPass<numPasses; nPass++)
  {
    int Types[4];
    SLightPass *lp = &m_RP.m_LPasses[nPass];
    lp->bRect = false;
    lp->nStencLTMask = 0;//nStencGroupLTMask;
    lp->nLTMask = lp->nLights;
#if !defined (XENON) && !defined(PS3)
    for (i=0; i<lp->nLights; i++)
    {
      SRenderLight *dl = lp->pLights[i];

//////////////////////////////////////////////////////////////////////////
      //TOFIX: don't rely on conseq light groups
      int nSLMask = 1<<dl->m_Id;
      lp->nStencLTMask |= nSLMask >> (nLightGroup*4);
//////////////////////////////////////////////////////////////////////////
      if (dl->m_Flags & DLF_POINT)
        Types[i] = SLMF_POINT;
      else
      if (dl->m_Flags & DLF_PROJECT)
      {
        Types[i] = SLMF_PROJECTED;
        assert(i == 0);
      }
      else
        Types[i] = SLMF_DIRECT;
    }
    switch(lp->nLights)
    {
    case 2:
      if (Types[0] > Types[1])
      {
        Exchange(Types[0], Types[1]);
        Exchange(lp->pLights[0], lp->pLights[1]);
      }
      break;
    case 3:
      if (Types[0] > Types[1])
      {
        Exchange(Types[0], Types[1]);
        Exchange(lp->pLights[0], lp->pLights[1]);
      }
      if (Types[0] > Types[2])
      {
        Exchange(Types[0], Types[2]);
        Exchange(lp->pLights[0], lp->pLights[2]);
      }
      if (Types[1] > Types[2])
      {
        Exchange(Types[1], Types[2]);
        Exchange(lp->pLights[1], lp->pLights[2]);
      }
      break;
    case 4:
      {
        for (int k=0; k<4; k++)
        {
          for (int j=i; j<4; j++)
          {
            if (Types[i] > Types[j])
            {
              Exchange(Types[i], Types[j]);
              Exchange(lp->pLights[i], lp->pLights[j]);
            }
          }
        }
      }
      break;
    }

    for (i=0; i<lp->nLights; i++)
    {
      lp->nLTMask |= Types[i] << (SLMF_LTYPE_SHIFT + i*SLMF_LTYPE_BITS);
    }













#endif
  }
  m_RP.m_nNumLightPasses = numPasses;
  if (m_RP.m_nShaderQuality != eSQ_Low)
  {
    if (numPasses == 1)
      CHWShader_D3D::mfSetLightParams(0);
  }
  return numPasses;
}

void CD3D9Renderer::FX_SetLightsScissor(SLightPass *pLP, const RectI* pDef)
{
  if (SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID] > 1)
    return;
  if (!pLP->nLights || (m_RP.m_FlagsShader_RT & g_HWSR_MaskBit[HWSR_AMBIENT]))
  {
		if (pDef)
			EF_Scissor(true, pDef->x, pDef->y, pDef->w, pDef->h);
		else
			EF_Scissor(false, 0, 0, 0, 0);
    return;
  }
  if (!pLP->bRect)
  {
    pLP->bRect = true;
    SRenderLight *pDL = pLP->pLights[0];
    pLP->rc = RectI(pDL->m_sX, pDL->m_sY, pDL->m_sWidth, pDL->m_sHeight);
    for (uint32 i=1; i<pLP->nLights; i++)
    {
      pDL = pLP->pLights[i];
      pLP->rc.Add(pDL->m_sX, pDL->m_sY, pDL->m_sWidth, pDL->m_sHeight);
    }
  }
  if (pLP->rc.w == m_width && pLP->rc.h == m_height)
	{
		if (pDef)
			EF_Scissor(true, pDef->x, pDef->y, pDef->w, pDef->h);
		else
			EF_Scissor(false, 0, 0, 0, 0);
	}
	else
	{
		if (pDef)
		{
			int x1 = max(pDef->x, pLP->rc.x);
			int x2 = min(pDef->x + pDef->w, pLP->rc.x + pLP->rc.w);
			int y1 = max(pDef->y, pLP->rc.y);
			int y2 = min(pDef->y + pDef->h, pLP->rc.y + pLP->rc.h);
			EF_Scissor(true, x1, y1, max(x2-x1, 0), max(y2-y1, 0));
		}
		else
			EF_Scissor(true, pLP->rc.x, pLP->rc.y, pLP->rc.w, pLP->rc.h);
	}
}

void CD3D9Renderer::FX_DrawMultiLightPasses(CShader *ef, SShaderTechnique *pTech, int nShadowChans)
{
	FUNCTION_PROFILER_RENDER_FLAT
  SShaderPass *slw;
  int32 i;

  PROFILE_FRAME(DrawShader_MultiLight_Passes);

  int nPasses = FX_SetupLightPasses(pTech);
  if (nPasses < 0)
    return;

  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];
  CRenderObject *pObj = rRP.m_pCurObject;

  if ((rRP.m_ObjFlags & FOB_BLEND_WITH_TERRAIN_COLOR) && rRP.m_pCurObject->m_nTextureID>0)
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_BLEND_WITH_TERRAIN_COLOR];
	else
    rRP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_BLEND_WITH_TERRAIN_COLOR];

	if (m_bTerrainAOEnabled && pTech->m_Flags & FHF_TERRAIN)
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_AMBIENT_OCCLUSION];
  
  //////////////////////////////////////////////////////////////////////////

	const CShadowUtils::ShadowFrustumIDs * pShadowFrustumIDs = NULL;
	if (pObj->m_bHasShadowCasters)
	{
		SRenderObjData * pOD = pObj->GetObjData(rRP.m_nProcessThreadID);
		const uint64 nShadowCasters = pOD ? pOD->m_ShadowCasters : 0;
		pShadowFrustumIDs = CShadowUtils::GetShadowFrustumList(nShadowCasters);
	}
  if ((ef->m_Flags2 & EF2_DEPTHMAP_SUBSURFSCATTER) && pShadowFrustumIDs)
  {
    if (SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID]!= 1)
    {
      assert(0);
    }
    //set separate scattering depth buffer
		for (CShadowUtils::ShadowFrustumIDs::const_iterator itFrID = pShadowFrustumIDs->begin();
			itFrID != pShadowFrustumIDs->end(); itFrID++)
    {
			ShadowMapFrustum * pShadowFrustum = CShadowUtils::GetFrustum(*itFrID);
      if (pShadowFrustum && pShadowFrustum->bForSubSurfScattering)
      {
        //configure first depth buffer  
        SetupShadowOnlyPass(0, pShadowFrustum, NULL);

        if (pShadowFrustum->bHWPCFCompare)
          m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_HW_PCF_COMPARE ];

        m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SHADOW_MIXED_MAP_G16R16];
        m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3]);
        m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
      }
    }
  } 

  //////////////////////////////////////////////////////////////////////////

  int nPass;
  rRP.m_PersFlags1 |= RBPF1_MULTILIGHTS;  
  for (nPass=0; nPass<nPasses; nPass++)
  {
    rRP.m_nCurLightPass = nPass;
    if (nPass && (rRP.m_FlagsShader_RT & g_HWSR_MaskBit[HWSR_AMBIENT]))
      rRP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_AMBIENT] | g_HWSR_MaskBit[HWSR_AMBIENT_OCCLUSION]);

    if (nPasses > 1 || rRP.m_nShaderQuality == eSQ_Low)
      CHWShader_D3D::mfSetLightParams(nPass);
    SLightPass *lp = &rRP.m_LPasses[nPass];

		if( !(rRP.m_nBatchFilter & FB_SCATTER) ) // Reminder for Nick: dynamically adjust scissor rect dimensions (take into account resolution)
		if (CV_r_optimisedlightsetup == 2 || CV_r_optimisedlightsetup == 3)
		{
			SRenderObjData* pOD = pObj->GetObjData(rRP.m_nProcessThreadID);
			if (pOD && pOD->m_scissorWidth && pOD->m_scissorHeight)
			{
				const RectI scissorRect(pOD->m_scissorX, pOD->m_scissorY, pOD->m_scissorWidth, pOD->m_scissorHeight);
				FX_SetLightsScissor(lp, &scissorRect);
			}
			else
				FX_SetLightsScissor(lp, 0);
		}
		
    rRP.m_FlagsShader_LT = lp->nLTMask;
#ifdef DO_RENDERLOG
    if (CRenderer::CV_r_log >= 3)
    {
      if (lp->nLights > 0)
      {
        if (nPass)
          Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n--- Lights: ");
        else
          Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "--- Lights: ");
        for (uint32 k=0; k<lp->nLights; k++)
        {
          Logv(0, "%s ", lp->pLights[k]->m_sName);
        }
        Logv(0, "\n");
      }
    }
#endif
    
    slw = &pTech->m_Passes[0];
    const int nTechPasses = pTech->m_Passes.Num();
    for (i=0; i<nTechPasses; i++, slw++)
    {
      m_RP.m_pCurPass = slw;

      // Set all textures and HW TexGen modes for the current pass
      //assert (slw->m_VShader && slw->m_PShader);
      if (!slw->m_VShader || !slw->m_PShader)
        continue;
      
      FX_CommitStates(pTech, slw, (slw->m_PassFlags & SHPF_NOMATSTATE) == 0);

			bool bSkinned = (m_RP.m_pCurObject->m_ObjFlags & FOB_CHARACTER) && !CV_r_character_nodeform;
			
#if defined(HW_INSTANCING_ENABLED)
      if (rRP.m_FlagsPerFlush & RBSI_INSTANCED && !bSkinned)
      {
        // Using geometry instancing approach
        FX_DrawShader_InstancedHW(ef, slw);
      }
      else
#endif
      {
        FX_DrawBatch(ef, slw);
      }      
    }

    // Should only be enabled per light pass (else if shader has more than 1 pass in technique will blend incorrect)
    rRP.m_bFirstPass = false;
  }
  rRP.m_bFirstPass = true;
  rRP.m_FlagsShader_LT = 0;
  rRP.m_nCurLightPass = 0;
  rRP.m_PersFlags1 &= ~RBPF1_MULTILIGHTS;
}

//=================================================================================

TArray<CRenderObject *> CD3D9Renderer::s_tempObjects[2];
TArray<SRendItem *> CD3D9Renderer::s_tempRIs;

//#if !defined(XENON) && !defined(PS3)

#define INST_PARAM_SIZE sizeof(Vec4)

// Actual drawing of instances
void CD3D9Renderer::FX_DrawInstances(CShader *ef, SShaderPass *slw, int nRE, uint32 nStartInst, uint32 nLastInst, uint32 nUsedAttr, byte *InstanceData, int nInstAttrMask, byte Attributes[], uint32 nConstBased, short dwCBufSlot)
{
  uint32 i;

  CHWShader_D3D *vp = (CHWShader_D3D *)slw->m_VShader;

  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;

  SRendItem** rRIs = &(rRP.m_RIs[nRE][0]);

#if defined (DIRECT3D10)
  // Don't render fallback in DX11
  if (!CHWShader_D3D::m_pCurInstVS || !CHWShader_D3D::m_pCurInstPS || CHWShader_D3D::m_pCurInstVS->m_bFallback || CHWShader_D3D::m_pCurInstPS->m_bFallback)
    return;
#endif




	uint32 nConstBasedInstancing = nConstBased;

	PREFAST_SUPPRESS_WARNING(6326)
  if (!nStartInst && nConstBasedInstancing != 2)
  {
    // Set the stream 3 to be per instance data and iterate once per instance
    rRP.m_PersFlags1 &= ~(RBPF1_USESTREAM<<3);
    int nCompared = 0;
    FX_CommitStreams(slw, false);
    int StreamMask = rRP.m_FlagsStreams_Decl >> 1;
    SVertexDeclaration *vd = 0;
    for (i=0; i<rRP.m_CustomVD.Num(); i++)
    {
      vd = rRP.m_CustomVD[i];
      if (vd->StreamMask == StreamMask && vd->VertFormat == rRP.m_CurVFormat && vd->InstAttrMask == nInstAttrMask)
        break;
    }
    if (i == rRP.m_CustomVD.Num())
    {
      vd = new SVertexDeclaration;
      rRP.m_CustomVD.AddElem(vd);
      vd->StreamMask = StreamMask;
      vd->VertFormat = rRP.m_CurVFormat;
      vd->InstAttrMask = nInstAttrMask;
      vd->m_pDeclaration = NULL;

			SOnDemandD3DVertexDeclaration Decl;
			EF_OnDemandVertexDeclaration(Decl,StreamMask,rRP.m_CurVFormat,false);

      int nElementsToCopy = Decl.m_Declaration.Num()-1;
#if defined (DIRECT3D10)
      nElementsToCopy++;
#endif
      for (i=0; i<(uint32)nElementsToCopy; i++)
      {
        vd->m_Declaration.AddElem(Decl.m_Declaration[i]);
      }
      int nInstOffs = 1;
#if defined (DIRECT3D9)
      D3DVERTEXELEMENT9 ve;
      ve.Stream = 3;
      ve.Method = D3DDECLMETHOD_DEFAULT;
      ve.Usage = D3DDECLUSAGE_TEXCOORD;
			PREFAST_SUPPRESS_WARNING(6326)
      if (nConstBasedInstancing == 1)
      {
        ve.Type = D3DDECLTYPE_FLOAT1;
        ve.UsageIndex = (BYTE)vp->m_pCurInst->m_nInstIndex;
        ve.Offset = 0;
        vd->m_Declaration.AddElem(ve);
      }
      else
      {
        ve.Type = D3DDECLTYPE_FLOAT4;
        for (i=0; i<nUsedAttr; i++)
        {
          ve.Offset = i*INST_PARAM_SIZE;
          ve.UsageIndex = Attributes[i]+nInstOffs;
          vd->m_Declaration.AddElem(ve);
        }








      }
      ve.Stream = 0xff;
      ve.Type = D3DDECLTYPE_UNUSED;
      ve.Usage = 0;
      ve.UsageIndex = 0;
      ve.Offset = 0;
      vd->m_Declaration.AddElem(ve);
#elif defined (DIRECT3D10)
      D3D11_INPUT_ELEMENT_DESC elemTC = {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 3, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1};      // texture
      if (nConstBasedInstancing == 1)
      {
        assert(0);
      }
      else
      {
        for (i=0; i<nUsedAttr; i++)
        {
          elemTC.AlignedByteOffset = i*INST_PARAM_SIZE;
          elemTC.SemanticIndex = Attributes[i]+nInstOffs;
          vd->m_Declaration.AddElem(elemTC);
        }
      }
#endif
    }
#if defined (DIRECT3D9)
		assert(vd);
    if (!vd->m_pDeclaration)
    {
      HRESULT hr = m_pd3dDevice->CreateVertexDeclaration(&vd->m_Declaration[0], &vd->m_pDeclaration);
      assert (hr == S_OK);
    }
    if (m_pLastVDeclaration != vd->m_pDeclaration)
    {
      m_pLastVDeclaration = vd->m_pDeclaration;
      HRESULT hr = m_pd3dDevice->SetVertexDeclaration(vd->m_pDeclaration);
      assert (hr == S_OK);
    }
#elif defined (DIRECT3D10)
    if (!vd->m_pDeclaration)
    {
			HRESULT hr = S_OK;
      assert(CHWShader_D3D::m_pCurInstVS && CHWShader_D3D::m_pCurInstVS->m_pShaderData);
      if (FAILED(hr = m_pd3dDevice->CreateInputLayout(&vd->m_Declaration[0], vd->m_Declaration.Num(), CHWShader_D3D::m_pCurInstVS->m_pShaderData, CHWShader_D3D::m_pCurInstVS->m_nDataSize, &vd->m_pDeclaration)))
      {
        assert(SUCCEEDED(hr));
        return;
      }
    }
    if (m_pLastVDeclaration != vd->m_pDeclaration)
    {
      m_pLastVDeclaration = vd->m_pDeclaration;
      m_pd3dDeviceContext->IASetInputLayout(vd->m_pDeclaration);
    }
#endif
  }

  int nInsts = nLastInst-nStartInst+1;
  {
    //PROFILE_FRAME(Draw_ShaderIndexMesh);
    int nPolysPerInst = rRP.m_RendNumIndices / 3;
#ifndef _RELEASE
		char instanceLabel[64];
		if(CV_r_geominstancingdebug)
		{
			snprintf(instanceLabel, 63, "Instances: %d", nInsts);
			PROFILE_LABEL_PUSH( instanceLabel );
		}
#endif
		


























#if defined (DIRECT3D9)
    if (rRP.m_pRE)
      rRP.m_pRE->mfDraw(ef, slw);
    else
      FX_DrawIndexedMesh(eptTriangleList);
































#else
    assert (rRP.m_pRE && rRP.m_pRE->mfGetType() == eDATA_Mesh);
    FX_Commit();
    D3D11_PRIMITIVE_TOPOLOGY eTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
#ifdef TESSELLATION_RENDERER
		if (CHWShader_D3D::m_pCurInstHS)
		{
			FX_SetAdjacencyOffsetBuffer();
			eTopology = D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST;
		}
#endif
    SetPrimitiveTopology(eTopology);
    m_pd3dDeviceContext->DrawIndexedInstanced(rRP.m_RendNumIndices, nInsts, rRP.m_FirstIndex+rRP.m_IndexOffset, 0, 0);
#endif

#ifndef _RELEASE
		if(CV_r_geominstancingdebug)
		{
			PROFILE_LABEL_POP( instanceLabel );
		}
#endif

#if defined(ENABLE_PROFILING_CODE)
		int nPolysAll = nPolysPerInst*nInsts;
		rRP.m_PS[rRP.m_nProcessThreadID].m_nPolygons[rRP.m_nPassGroupDIP] += rRP.m_RendNumIndices/3;
		rRP.m_PS[rRP.m_nProcessThreadID].m_nDIPs[rRP.m_nPassGroupDIP]+=nInsts;
		rRP.m_PS[rRP.m_nProcessThreadID].m_nPolygons[rRP.m_nPassGroupDIP] += nPolysAll;
		rRP.m_PS[rRP.m_nProcessThreadID].m_nInsts+=nInsts;
		rRP.m_PS[rRP.m_nProcessThreadID].m_nInstCalls++;
#if defined(ENABLE_STATOSCOPE_RELEASE)
    rRP.m_PS[rRP.m_nProcessThreadID].m_RendHWInstancesPolysOne += nPolysPerInst;
    rRP.m_PS[rRP.m_nProcessThreadID].m_RendHWInstancesPolysAll += nPolysAll;
    rRP.m_PS[rRP.m_nProcessThreadID].m_NumRendHWInstances += nInsts;
    rRP.m_PS[rRP.m_nProcessThreadID].m_RendHWInstancesDIPs++;
#endif
#endif
  }
}

#define MAX_HWINST_PARAMS_CONST (240 - VSCONST_INSTDATA)



#if defined(_CPU_SSE) && !defined(_DEBUG)
typedef __m128 fVector4;
#else
typedef float fVector4;
#endif


// Draw geometry instances in single DIP using HW geom. instancing (StreamSourceFreq)
void CD3D9Renderer::FX_DrawShader_InstancedHW(CShader *ef, SShaderPass *slw)
{
#if defined(HW_INSTANCING_ENABLED)
  PROFILE_FRAME(DrawShader_Instanced);

  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];

  // Set culling mode
  if (!(rRP.m_FlagsPerFlush & RBSI_LOCKCULL))
  {
    if (slw->m_eCull != -1)
      D3DSetCull((ECull)slw->m_eCull);
  }
  
	bool bProcessedAll = true;
  
  uint32 i, j, n;
  CHWShader_D3D *vp = (CHWShader_D3D *)slw->m_VShader;
  CHWShader_D3D *ps = (CHWShader_D3D *)slw->m_PShader;
  uint32 nOffs;
  Matrix44 m;
  SCGBind bind;
  byte Attributes[32];

  rRP.m_FlagsPerFlush |= RBSI_INSTANCED;

  uint32 nCurInst;
  byte *data = NULL;
  SRenderShaderResources *pCurRes = rRP.m_pShaderResources;
  SRenderShaderResources *pSaveRes = pCurRes;

	uint64 nRTFlags = rRP.m_FlagsShader_RT;
	uint64 nSaveRTFlags = nRTFlags;

	const int nInstType = CV_r_geominstancing;
	// batch further and send everything as if it's rotated (full 3x4 matrix), even if we could
	// just send position



	enum { nConstBasedInstancing = 0 };


	uint64 * __restrict maskBit = g_HWSR_MaskBit;
	
	if (nConstBasedInstancing)
		nRTFlags |= maskBit[HWSR_INSTANCING_CONST];
	else
		nRTFlags |= maskBit[HWSR_INSTANCING_ATTR];

	if(CV_r_geominstancingdebug > 1)
	{
		// !DEBUG0 && !DEBUG1 && DEBUG2 && DEBUG3
		nRTFlags &= ~(maskBit[HWSR_DEBUG0]|maskBit[HWSR_DEBUG1]);
		nRTFlags |= (maskBit[HWSR_DEBUG2]|maskBit[HWSR_DEBUG3]);
	}

	rRP.m_FlagsShader_RT = nRTFlags;
	
	// Set Vertex shader
	if (!vp->mfSet(HWSF_INSTANCED))
	{
		rRP.m_ReqStreamFrequence[0] = 1;
		rRP.m_ReqStreamFrequence[3] = 1;
		rRP.m_pShaderResources = pSaveRes;
		rRP.m_PersFlags1 |= RBPF1_USESTREAM<<3;
		return;
	}

	CHWShader_D3D::SHWSInstance *pVPInst = vp->m_pCurInst;

	short dwCBufSlot = 0;







	

















	// Set Pixel shader and all associated textures
	if (!ps->mfSet(HWSF_SETTEXTURES))
	{
		rRP.m_ReqStreamFrequence[0] = 1;
		rRP.m_ReqStreamFrequence[3] = 1;
		rRP.m_pShaderResources = pSaveRes;
		rRP.m_PersFlags1 |= RBPF1_USESTREAM<<3;
		return;
	}

	bool bTessEnabled = false;
#if defined(DIRECT3D10) && !defined(PS3) && !defined(CAFE)
	CHWShader_D3D *curGS = (CHWShader_D3D *)slw->m_GShader;
	if (curGS)
		curGS->mfSet(0);
	else
		CHWShader_D3D::mfBindGS(NULL, NULL);
	
	#ifdef TESSELLATION_RENDERER
		CHWShader_D3D *pCurHS, *pCurDS;
		bTessEnabled = FX_SetTessellationFlags(pCurHS, pCurDS, slw);
		if (bTessEnabled)
		{
			pCurHS->mfSetHS(0);
			pCurDS->mfSetDS(HWSF_SETTEXTURES);
		}
		else
		{
			CHWShader_D3D::mfBindHS(NULL, NULL);
			CHWShader_D3D::mfBindDS(NULL, NULL);
		}
	#else
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
	#endif

	CHWShader_D3D *curCS = (CHWShader_D3D *)slw->m_CShader;
	if (curCS)
		curCS->mfSetCS(0);
	else
		CHWShader_D3D::mfBindCS(NULL, NULL);
#endif
	
  if (!pVPInst || pVPInst->m_bFallback || (ps->m_pCurInst && ps->m_pCurInst->m_bFallback))
	{
		return;
	}

	ps->mfSetParametersPI(NULL, NULL);

#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
	if (curGS)
		curGS->mfSetParametersPI(NULL, NULL);
#endif

	int nUsedAttr = 3;
	int nInstAttrMask = 0;












	Attributes[0] = (byte)pVPInst->m_nInstMatrixID;
	Attributes[1] = Attributes[0]+1;
	Attributes[2] = Attributes[0]+2;
	nInstAttrMask = 0x7 << pVPInst->m_nInstMatrixID;
	if (pVPInst->m_nParams_Inst >= 0)
	{
		SCGParamsGroup& Group = CGParamManager::m_Groups[pVPInst->m_nParams_Inst];
		uint32 nSize = Group.nParams;
		for (j=0; j<nSize; j++)
		{
			SCGParam *pr = &Group.pParams[j];
			for (uint32 na=0; na<(uint32)pr->m_nParameters; na++)
			{
				Attributes[nUsedAttr+na] = pr->m_dwBind+na;
				nInstAttrMask |= 1<<Attributes[nUsedAttr+na];
			}
			nUsedAttr += pr->m_nParameters;
		}
	}






	CRendElementBase *pRE = NULL;
	CRenderMesh *pRenderMesh = NULL;

	const int nLastRE = rRP.m_nLastRE;
  for (int nRE=0; nRE<=nLastRE; nRE++)
  {
		uint32 nRIs = rRP.m_RIs[nRE].size();
    SRendItem ** rRIs = &(rRP.m_RIs[nRE][0]);

		// don't process REs that don't make the cut for instancing.
		// these were batched with an instance-ready RE, so leave this to drop through into DrawBatch
		if(nRIs <= (uint32)CRenderer::m_iGeomInstancingThreshold)
		{
			bProcessedAll = false;
			continue;
		}
		
    SRenderShaderResources *pRes = SRendItem::mfGetRes(rRIs[0]->SortVal);
    pRE = rRP.m_pRE = rRIs[0]->pElem;


		EVertexFormat curVFormat = eVF_Unknown;
		CREMeshImpl* __restrict pMesh = (CREMeshImpl*) pRE;

    // pRE->mfPrepare(false); // we always use meshes. Just inline relevant code
		{
			curVFormat = rRP.m_CurVFormat = pMesh->m_pRenderMesh->_GetVertexFormat();

			rRP.m_FirstVertex = pMesh->m_nFirstVertId;
			rRP.m_FirstIndex =  pMesh->m_nFirstIndexId;
			rRP.m_RendNumIndices = pMesh->m_nNumIndices;
			rRP.m_RendNumVerts = pMesh->m_nNumVerts;
		}

    {
      if (pCurRes != pRes)
      {
				rRP.m_pShaderResources = pRes;
				vp->mfSetParametersPB();
				ps->mfSetParametersPB();
				if (ps->m_pCurInst)
					ps->mfSetSamplers(ps->m_pCurInst->m_pSamplers, eHWSC_Pixel);
#ifdef TESSELLATION_RENDERER
				if (pCurDS && pCurDS->m_pCurInst)
					pCurDS->mfSetSamplers(pCurDS->m_pCurInst->m_pSamplers, eHWSC_Domain);
#endif
        rRP.m_nCommitFlags |= FC_PER_BATCH_PARAMS | FC_MATERIAL_PARAMS;
        pCurRes = pRes;
      }

			if(pMesh->m_pRenderMesh != pRenderMesh)
			{
				// Create/Update video mesh (VB management)
				if (!pRE->mfCheckUpdate(curVFormat, rRP.m_FlagsStreams_Stream, rTI.m_nFrameUpdateID, bTessEnabled))
				{
					rRP.m_ReqStreamFrequence[0] = 1;
					rRP.m_ReqStreamFrequence[3] = 1;
					rRP.m_pShaderResources = pSaveRes;
					rRP.m_PersFlags1 |= RBPF1_USESTREAM<<3;
					return;
				}

				if(nConstBasedInstancing)
				{
					bool bRes = true;

					// for meshes and RE set, inline relevant code
					//bRes = FX_CommitStreams(slw, true);
					{
						uint32 nFlagsStreams_Stream = rRP.m_FlagsStreams_Stream;
#if ENABLE_NORMALSTREAM_SUPPORT
						if (CHWShader_D3D::m_pCurInstHS)
						{
							nFlagsStreams_Stream |= (1<<VSF_NORMALS);
							rRP.m_FlagsStreams_Decl |= (1<<VSF_NORMALS);
						}
						rRP.m_FlagsStreams_Stream = nFlagsStreams_Stream;
#endif

						HRESULT hr;	
						//if (bSetVertexDecl)
						{
							hr = FX_SetVertexDeclaration(nFlagsStreams_Stream, curVFormat);
#ifndef _RELEASE
							if (FAILED(hr))
								bRes = false;
#endif
						}

						if(bRes)
						{
							bRes = pMesh->mfPreDraw(slw);
						}
					}

					if(!bRes)
						continue;
				}

				pRenderMesh = pMesh->m_pRenderMesh;
			}






      {
        nCurInst = 0;

        // Detects possibility of using attributes based instancing
        // If number of used attributes exceed 16 we can't use attributes based instancing (switch to constant based)
        int nStreamMask = rRP.m_FlagsStreams_Stream >> 1;
        int nVFormat = rRP.m_CurVFormat;
        uint32 nCO = 0;
        int nCI = 0;
			  uint32 dwDeclarationSize = 0;	// todo: later m_RP.m_D3DVertexDeclaration[nStreamMask][nVFormat].m_Declaration.Num();
        if (!nConstBasedInstancing && dwDeclarationSize+nUsedAttr-1 > 16)
          iLog->LogWarning("WARNING: Attributes based instancing cannot exceed 16 attributes (%s uses %d attr. + %d vertex decl.attr.)[VF: %d, SM: 0x%x]", vp->GetName(), nUsedAttr, dwDeclarationSize-1, nVFormat, nStreamMask);
        else
        while ((int)nCurInst < nRIs)
        {
          uint32 nLastInst = nRIs - 1;









          {
            uint32 nParamsPerInstAllowed = nConstBasedInstancing ? MAX_HWINST_PARAMS_CONST : MAX_HWINST_PARAMS;
            if ((nLastInst-nCurInst+1)*nUsedAttr >= nParamsPerInstAllowed)
              nLastInst = nCurInst+(nParamsPerInstAllowed/nUsedAttr)-1;
          }
          byte *inddata = NULL;
          if (nConstBasedInstancing)
          {


    #if defined (DIRECT3D9)
            data = (byte *)&CHWShader_D3D::m_CurVSParams[VSCONST_INSTDATA].x;
            if (nInstType != 3)
              inddata = (byte *)rRP.m_VB_Inst->LockVB((nLastInst-nCurInst+1)*nUsedAttr*sizeof(float), nOffs);
    #else
            assert(0);
    #endif
          }
          else
          {
            data = (byte *)rRP.m_VB_Inst->LockVB((nLastInst-nCurInst+1)*nUsedAttr, nOffs);
            nOffs *= INST_PARAM_SIZE;
          }
          CRenderObject *curObj = rRP.m_pCurObject;
          n = 0;

					// 3 float4 = inst Matrix
					const uint32 nStride = nUsedAttr*sizeof(float[4]);

          // Fill the stream 3 for per-instance data
          CRenderObject *pRO;
          SInstanceInfo *pI;
					byte *pWalkData = data;
          for (i=nCurInst; i<=nLastInst; i++, n++)
          {
						fVector4* __restrict vMatrix = (fVector4*)pWalkData;

            {
              pRO = rRIs[nCO++]->pObj;
#ifndef _DEBUG




#endif
              rRP.m_pCurObject = pRO;
              pI = &pRO->m_II;
            }
            register const float * fSrc = pI->m_Matrix.GetData();






#if defined(_CPU_SSE) && !defined(_DEBUG)
						vMatrix[0] = _mm_load_ps(&fSrc[0]);
						vMatrix[1] = _mm_load_ps(&fSrc[4]);
						vMatrix[2] = _mm_load_ps(&fSrc[8]);
#else
						vMatrix[0] = fSrc[0];  vMatrix[1] = fSrc[1];  vMatrix[2] = fSrc[2];  vMatrix[3] = fSrc[3]; 
						vMatrix[4] = fSrc[4];  vMatrix[5] = fSrc[5];  vMatrix[6] = fSrc[6];  vMatrix[7] = fSrc[7]; 
						vMatrix[8] = fSrc[8];  vMatrix[9] = fSrc[9];  vMatrix[10] = fSrc[10];  vMatrix[11] = fSrc[11]; 
#endif

            float * __restrict fParm = (float *)&pWalkData[3*sizeof(float[4])];
						pWalkData += nStride;

#ifdef DO_RENDERLOG
            if (CRenderer::CV_r_log >= 3)
              Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "Inst Pos: (%.3f, %.3f, %.3f, %.3f)\n", fSrc[3], fSrc[7], fSrc[11], fSrc[0]);
#endif

            if (pVPInst->m_nParams_Inst >= 0)
            {
              SCGParamsGroup& Group = CGParamManager::m_Groups[pVPInst->m_nParams_Inst];
							







	#if defined (DIRECT3D9)
							fParm = vp->mfSetParametersPI(Group.pParams, Group.nParams, fParm, eHWSC_Vertex);
	#else
							fParm = vp->mfSetParametersPI(Group.pParams, Group.nParams, fParm, eHWSC_Vertex, 40);
	#endif

            }
          }
          rRP.m_pCurObject = curObj;




          rRP.m_VB_Inst->UnlockVB();

					#if defined(DIRECT3D9) && !defined(XENON)
          if (nConstBasedInstancing)
          {
            vp->mfParameterReg_NoCheck(VSCONST_INSTDATA, &CHWShader_D3D::m_CurVSParams[VSCONST_INSTDATA].x, n*nUsedAttr, eHWSC_Vertex);
          }
					#endif

          // Set the first stream to be the indexed data and render N instances
					PREFAST_SUPPRESS_WARNING(6326)
          if (nConstBasedInstancing != 2)
          {
  #ifndef XENON
            rRP.m_ReqStreamFrequence[0] = n | D3DSTREAMSOURCE_INDEXEDDATA;
            if (nConstBasedInstancing == 1)
              rRP.m_VB_Inst->Bind(3, nOffs, sizeof(float), 1 | D3DSTREAMSOURCE_INSTANCEDATA);
            else
              rRP.m_VB_Inst->Bind(3, nOffs, nUsedAttr*INST_PARAM_SIZE, 1 | D3DSTREAMSOURCE_INSTANCEDATA);


  #endif
					}

          FX_DrawInstances(ef, slw, nRE, nCurInst, nLastInst, nUsedAttr, data, nInstAttrMask, Attributes, nConstBasedInstancing, dwCBufSlot);

          nCurInst = nLastInst+1;
        }
      }
    }
  }
#ifdef TESSELLATION_RENDERER
	if (bTessEnabled)
	{
		CHWShader_D3D::mfBindDS(NULL, NULL);
		CHWShader_D3D::mfBindHS(NULL, NULL);
	}
#endif

	rRP.m_PersFlags1 |= RBPF1_USESTREAM<<3;
  rRP.m_ReqStreamFrequence[0] = 1;
  rRP.m_ReqStreamFrequence[3] = 1;
  rRP.m_pShaderResources = pSaveRes;
	rRP.m_nCommitFlags = FC_ALL;
  rRP.m_FlagsShader_RT = nSaveRTFlags;
	rRP.m_nNumRendPasses++;
	if(!bProcessedAll)
	{
		FX_DrawBatch(ef, slw);
	}
#else
	CryFatalError("HW Instancing not supported on this platform");
#endif
}
//#endif

//====================================================================================

void CD3D9Renderer::FX_FlushSkinVSParams(CHWShader_D3D *pVS, int nFirst, int nBones, int nOffsVS, int numBonesPerChunk, int nSlot, QuatTS *pSkinQuats, QuatTS *pMBSkinQuats)
{
	FUNCTION_PROFILER_RENDER_FLAT
#if defined (DIRECT3D9)
  pVS->mfSetVSConst(VSCONST_SKINMATRIX + (nOffsVS<<1), &pSkinQuats[nFirst].q.v.x, nBones<<1);
  if ((m_RP.m_PersFlags2 & RBPF2_MOTIONBLURPASS) && (numBonesPerChunk <= NUM_MAX_BONES_PER_GROUP_WITH_MB) )
  { 
    // if in motion blur pass, and bones count is less than NUM_MAX_BONES_PER_GROUP_WITH_MB, allow previous frame skinning
    pVS->mfSetVSConst(VSCONST_SKINMATRIX + ((nOffsVS + NUM_MAX_BONES_PER_GROUP_WITH_MB)<<1), &pMBSkinQuats[nFirst].q.v.x, nBones<<1);
  }                      
#elif defined (DIRECT3D10)




  if (nSlot>=0)
  {
    int nVecs = VSCONST_SKINMATRIX+numBonesPerChunk * 2;
    if ((m_RP.m_PersFlags2 & RBPF2_MOTIONBLURPASS) && (numBonesPerChunk <= NUM_MAX_BONES_PER_GROUP_WITH_MB) )
      nVecs += NUM_MAX_BONES_PER_GROUP_WITH_MB * 2;
    pVS->mfParameterReg(VSCONST_SKINMATRIX + (nOffsVS<<1), nSlot, eHWSC_Vertex, &pSkinQuats[nFirst].q.v.x, (nBones<<1), nVecs);
    if ((m_RP.m_PersFlags2 & RBPF2_MOTIONBLURPASS) && (numBonesPerChunk <= NUM_MAX_BONES_PER_GROUP_WITH_MB) )
    { 
      // if in motion blur pass, and bones count is less than NUM_MAX_BONES_PER_GROUP_WITH_MB, allow previous frame skinning
      pVS->mfParameterReg(VSCONST_SKINMATRIX + ((nOffsVS + NUM_MAX_BONES_PER_GROUP_WITH_MB)<<1), nSlot, eHWSC_Vertex, &pMBSkinQuats[nFirst].q.v.x, (nBones<<1), nVecs);
    }                      
  }
#endif
}

//for PS3 it is inlined as it is very simple and requires some loads when it is not inlined
#ifndef PS3
byte CD3D9Renderer::FX_StartQuery(SRendItem *pRI)
{
	if(!CV_r_ConditionalRendering || !(m_RP.m_nBatchFilter & (FB_Z|FB_GENERAL)))
		return 0;
#if defined(DIRECT3D9) || defined(DIRECT3D10)
	if (m_RP.m_nBatchFilter & FB_Z)
	{
		if (m_OcclQueriesUsed >= MAX_OCCL_QUERIES)
			return 0;

		assert(pRI->nOcclQuery > MAX_OCCL_QUERIES);
		uint32 nQuery = m_OcclQueriesUsed;
		++m_OcclQueriesUsed;
		COcclusionQuery *pQ = &m_OcclQueries[nQuery];
		pQ->BeginQuery();
		pRI->nOcclQuery = nQuery;
#ifndef _RELEASE
		m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumQIssued++;
#endif
		return 1;
	}
	else
	{
		if (pRI->nOcclQuery >= MAX_OCCL_QUERIES || pRI->nOcclQuery<0)
			return 0;

		COcclusionQuery *pQ = &m_OcclQueries[pRI->nOcclQuery];
#ifndef _RELEASE
		CTimeValue Time = iTimer->GetAsyncTime();
#endif
		uint32 nPixels = pQ->GetVisibleSamples(CV_r_ConditionalRendering==2 ? false : true);
#ifndef _RELEASE
		m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumQStallTime+=static_cast<int>(iTimer->GetAsyncTime().GetMilliSeconds()-Time.GetMilliSeconds());
#endif
		bool bReady = pQ->IsReady();
		if (!bReady)
		{
#ifndef _RELEASE
			m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumQNotReady++;
#endif
			return 0;
		}
		if (nPixels == 0)
		{
#ifndef _RELEASE
			m_RP.m_PS[m_RP.m_nProcessThreadID].m_NumQOccluded++;
#endif
			return 2;
		}
		return 0;
	}
#endif
	return 0;
}
#endif//PS3

void CD3D9Renderer::FX_EndQuery(SRendItem *pRI, byte bStartQ)
{






#if defined(DIRECT3D9) || defined(DIRECT3D10)
  if (!bStartQ)
    return;

	assert(pRI->nOcclQuery < MAX_OCCL_QUERIES);
  COcclusionQuery *pQ = &m_OcclQueries[pRI->nOcclQuery];
  pQ->EndQuery();
#endif
}

void CD3D9Renderer::FX_DrawBatchSkinned(CShader *pSh, SShaderPass *pPass, ISkinnable *pCharInstance)
{
	FUNCTION_PROFILER_RENDER_FLAT
  PROFILE_FRAME(DrawShader_BatchSkinned);

  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];

	CHWShader_D3D *pCurVS = (CHWShader_D3D *)pPass->m_VShader;
	CHWShader_D3D *pCurPS = (CHWShader_D3D *)pPass->m_PShader;
	bool bTessEnabled = false;
#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
	CHWShader_D3D *pCurGS = (CHWShader_D3D *)pPass->m_GShader;
	#ifdef TESSELLATION_RENDERER
		CHWShader_D3D *pCurHS, *pCurDS;
		bTessEnabled = FX_SetTessellationFlags(pCurHS, pCurDS, pPass);
	#else
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
	#endif
#endif

  int nThreadID = m_RP.m_nProcessThreadID;
#ifndef _RELEASE
  rRP.m_PS[nThreadID].m_NumRendSkinnedObjects++;
#endif
  QuatTS *pGlobalSkinQuatsL = NULL;
  QuatTS *pGlobalSkinQuatsS = NULL;
  QuatTS *pMBGlobalSkinQuatsL = NULL;
  QuatTS *pMBGlobalSkinQuatsS = NULL;
  Vec4A HWShapeDeformationData[8];
  CRenderObject *pObj = rRP.m_pCurObject;
  uint32 HWSkinningFlags = 0;
  CREMeshImpl* pRE = (CREMeshImpl*) rRP.m_pRE;





  uint32 nBones = 0;
  uint32 j;

  uint8 * pRemapTable = 0;

  //if (pObj->m_pCharInstance && !CV_r_character_nodeform)
  {
    PROFILE_FRAME(Objects_GetSkinningData);
    int nFlags = 0;
    {
      HWSkinningFlags |= (rRP.m_PersFlags2 & RBPF2_MOTIONBLURPASS)? eHWS_MotionBlured: 0;
      HWSkinningFlags |= eHWS_MorphTarget;
      SRenderObjData *pOD = pObj->GetObjData(nThreadID);
      assert(pOD);
      if (pOD)    
			{
				nBones = pCharInstance->GetSkeletonPose(pObj->m_nLod, nThreadID, pObj->m_II.m_Matrix, pGlobalSkinQuatsL, pGlobalSkinQuatsS, pMBGlobalSkinQuatsL, pMBGlobalSkinQuatsS, HWShapeDeformationData, HWSkinningFlags, pRemapTable);
			}
    }
  }
  CRenderChunk *pChunk = pRE->m_pChunk;



  if (nBones < pChunk->m_arrChunkBoneIDs.size() || pChunk->m_arrChunkBoneIDs.empty())
  {
    Warning ("Warning: Skinned geometry number of bones mismatch (Mesh: %d, Character instance: %d)", pChunk->m_arrChunkBoneIDs.size(), nBones);
  }
  if (!pGlobalSkinQuatsL && !pGlobalSkinQuatsS)
  {
    Warning ("Warning: Animation system returned NULL Quaternions ptr");
  }
  else
  {
		CRenderMesh* pRenderMesh = pRE->m_pRenderMesh;
		bool bSpuSkin = false;






    if (HWSkinningFlags & eHWS_MorphTarget)
    {
      rRP.m_FlagsStreams_Decl |= VSM_HWSKIN_MORPHTARGET;
      rRP.m_FlagsStreams_Stream |= VSM_HWSKIN_MORPHTARGET;
    }
#if ENABLE_SHAPEDEFORMATION_SUPPORT
    if (HWSkinningFlags & eHWS_ShapeDeform)
    {
      rRP.m_FlagsStreams_Decl |= VSM_HWSKIN_SHAPEDEFORM;
      rRP.m_FlagsStreams_Stream |= VSM_HWSKIN_SHAPEDEFORM;
    }
#endif

    rRP.m_nNumRendPasses++;

    rRP.m_RendNumGroup = 0;
    rRP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SKELETON_SSD]);

		if (!bSpuSkin)
		{
    	//always use 4 bone per vertex
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SKELETON_SSD];
		}
    rRP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_MORPHTARGET] | g_HWSR_MaskBit[HWSR_SHAPEDEFORM]);
    if (HWSkinningFlags & eHWS_MorphTarget)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_MORPHTARGET];

    if (HWSkinningFlags & eHWS_ShapeDeform)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SHAPEDEFORM];

#if !defined (DIRECT3D10)
    // Disable perlin-noise based deformations on skinned meshes
    int nMDF = rRP.m_FlagsShader_MDV & 0xf;
    if (nMDF == eDT_Perlin3D || nMDF == eDT_Perlin2D)
      rRP.m_FlagsShader_MDV &= ~0xf;
#endif

    if (pRemapTable) 
    {
      // Set shaders
      bool bRes = pCurPS->mfSetPS(HWSF_SETTEXTURES);
      bRes &= pCurVS->mfSetVS(0);

#ifdef TESSELLATION_RENDERER
			if (bTessEnabled)
			{
				bRes &= pCurHS->mfSetHS(0);
				bRes &= pCurDS->mfSetDS(HWSF_SETTEXTURES);
			}
			else
			{
				CHWShader_D3D::mfBindHS(NULL, NULL);
				CHWShader_D3D::mfBindDS(NULL, NULL);
			}

			if (pCurGS)
				bRes &= pCurGS->mfSetGS(0);
			else
				CHWShader_D3D::mfBindGS(NULL, NULL);
#endif

      if (bRes)
      {
#if defined (DIRECT3D10)
        if (CHWShader_D3D::m_pCurInstVS && CHWShader_D3D::m_pCurInstVS->m_bFallback)
          return;
#endif
        // Create/Update video mesh (VB management)
        if (!pRE->mfCheckUpdate(m_RP.m_CurVFormat, m_RP.m_FlagsStreams_Stream, rTI.m_nFrameUpdateID, bTessEnabled))
          return;

        uint32 numBonesPerChunk=pChunk->m_arrChunkBoneIDs.size();
        assert( numBonesPerChunk <= NUM_MAX_BONES_PER_GROUP );

        if (pGlobalSkinQuatsS) 
        {




          int nSlot = -1;
#if defined (DIRECT3D10)
					static const CCryNameR Name_g_SkinQuat("_g_SkinQuat");
          SCGBind *pBind = pCurVS->mfGetParameterBind(Name_g_SkinQuat);
          if (pBind)
            nSlot = pBind->m_dwCBufSlot;
#endif
          int nFirst = pRemapTable[pChunk->m_arrChunkBoneIDs[0]];
          int nLast = nFirst;
          int nOffs = 0;
          for (j=1; j<numBonesPerChunk; j++)
          {
            uint32 BoneID=pRemapTable[pChunk->m_arrChunkBoneIDs[j]];
            if (BoneID != nLast+1)
            {
              FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsS, pMBGlobalSkinQuatsS);
              nFirst = BoneID;
              nOffs = j;
            }
            nLast = BoneID;
          }
          FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsS, pMBGlobalSkinQuatsS);
        }
        else
        {
          int nSlot = -1;
#if defined (DIRECT3D10)
					static const CCryNameR Name_g_SkinQuat("_g_SkinQuat");
          SCGBind *pBind = pCurVS->mfGetParameterBind(Name_g_SkinQuat);
          assert(pBind);
          if (pBind)
            nSlot = pBind->m_dwCBufSlot;
#endif
          int nFirst = pRemapTable[pChunk->m_arrChunkBoneIDs[0]];
          int nLast = nFirst;
          int nOffs = 0;
          for (j=1; j<numBonesPerChunk; j++)
          {
            uint32 BoneID=pRemapTable[pChunk->m_arrChunkBoneIDs[j]];
            if (BoneID != nLast+1)
            {
              FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsL, pMBGlobalSkinQuatsS);
              nFirst = BoneID;
              nOffs = j;
            }
            nLast = BoneID;
          }
          FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsL, pMBGlobalSkinQuatsS);
        }

        if (HWSkinningFlags & eHWS_ShapeDeform)
        {
#if defined (DIRECT3D9)
          pCurVS->mfSetVSConst(VSCONST_SHAPEDEFORMATION, &HWShapeDeformationData[0].x, 8);
#elif defined (DIRECT3D10)
					static const CCryNameR Name_g_ShapeDeformationData("_g_ShapeDeformationData");
          SCGBind *pBind = pCurVS->mfGetParameterBind(Name_g_ShapeDeformationData);
	#ifndef PS3
          assert(pBind);
	#endif
          if (pBind)
            pCurVS->mfParameterReg(VSCONST_SHAPEDEFORMATION, pBind->m_dwCBufSlot, eHWSC_Vertex, &HWShapeDeformationData[0].x, 8, VSCONST_SHAPEDEFORMATION+8);
#endif
        }
        
				if (ShouldApplyFogCorrection())
					FX_FogCorrection();

        // Unlock all VB (if needed) and set current streams
        if (FX_CommitStreams(pPass))
        {
          uint32 nObj = 0;
          CRenderObject *pSaveObj = rRP.m_pCurObject;
          CRenderObject *pObject;
          for (nObj=0; nObj<rRP.m_RIs[0].Num(); nObj++)
          {
            pObject = rRP.m_RIs[0][nObj]->pObj;
            rRP.m_pCurObject = pObject;

#ifdef DO_RENDERSTATS
            if( (CV_r_stats==6 || m_pDebugRenderNode || m_bCollectDrawCallsInfo) && !(rTI.m_PersFlags & RBPF_MAKESPRITE) ) 
              FX_TrackStats(pObject, pRE->m_pRenderMesh);
#endif

#ifdef DO_RENDERLOG
            if (CRenderer::CV_r_log >= 3)
            {
              Vec3 vPos = pObject->GetTranslation();
              Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], "+++ HWSkin Group Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_nNumRendPasses, pObject->m_Id, vPos[0], vPos[1], vPos[2]);
            }
#endif




						if (rRP.m_nBatchFilter & FB_MOTIONBLUR)
						{
							int test = 1;
						}

            pCurVS->mfSetParametersPI(pObject, pSh);
            pCurPS->mfSetParametersPI(NULL, NULL);

#if defined(DIRECT3D10) && !defined(PS3) && !defined(CAFE)
            if (pCurGS)
              pCurGS->mfSetParametersPI(NULL, NULL);
            else
              CHWShader_D3D::mfBindGS(NULL, NULL);
#endif

            {
              //PROFILE_FRAME(Draw_ShaderIndexMesh);
              if (rRP.m_pRE)
                rRP.m_pRE->mfDraw(pSh, pPass);
              else
                FX_DrawIndexedMesh(eptTriangleList);
            }
          }
          rRP.m_FlagsShader_MD &= ~(HWMD_TCM | HWMD_TCG);
          if (pSaveObj != rRP.m_pCurObject)
          {
            rRP.m_pCurObject = pSaveObj;
          }
        }
      }

    }
    else
    {
			// Set shaders
			bool bRes = pCurPS->mfSetPS(HWSF_SETTEXTURES);
			bRes &= pCurVS->mfSetVS(0);
#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
			if (pCurGS)
				bRes &= pCurGS->mfSetGS(0);
			else
				CHWShader_D3D::mfBindGS(NULL, NULL);
	#ifdef TESSELLATION_RENDERER
			if (bTessEnabled)
			{
				bRes &= pCurHS->mfSetHS(0);
				bRes &= pCurDS->mfSetDS(HWSF_SETTEXTURES);
			}
			else
			{
				CHWShader_D3D::mfBindDS(NULL, NULL);
				CHWShader_D3D::mfBindHS(NULL, NULL);
			}
	#endif
#endif

      if (bRes)
      {
#if defined (DIRECT3D10)
        if (CHWShader_D3D::m_pCurInstVS && CHWShader_D3D::m_pCurInstVS->m_bFallback)
          return;
#endif
        // Create/Update video mesh (VB management)
        if (!pRE->mfCheckUpdate(rRP.m_CurVFormat, rRP.m_FlagsStreams_Stream, rTI.m_nFrameUpdateID, bTessEnabled))
          return;

        uint32 numBonesPerChunk=pChunk->m_arrChunkBoneIDs.size();
        assert( numBonesPerChunk <= NUM_MAX_BONES_PER_GROUP );
        numBonesPerChunk = min( numBonesPerChunk, (uint32)NUM_MAX_BONES_PER_GROUP );

				if(numBonesPerChunk)
				{
					if (pGlobalSkinQuatsS) 
					{
						int nSlot = -1;
	#if defined (DIRECT3D10)
						static const CCryNameR Name_g_SkinQuat("_g_SkinQuat");
						SCGBind *pBind = pCurVS->mfGetParameterBind(Name_g_SkinQuat);
						assert(pBind);
						if (pBind)
							nSlot = pBind->m_dwCBufSlot;
	#endif
						int nFirst = pChunk->m_arrChunkBoneIDs[0];
						int nLast = nFirst;
						int nOffs = 0;
						for (j=1; j<numBonesPerChunk; j++)
						{
							uint32 BoneID=pChunk->m_arrChunkBoneIDs[j];
							if (BoneID != nLast+1)
							{
								FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsS, pMBGlobalSkinQuatsS);
								nFirst = BoneID;
								nOffs = j;
							}
							nLast = BoneID;
						}
						FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsS, pMBGlobalSkinQuatsS);
					}
					else
					{
						int nSlot = -1;
	#if defined (DIRECT3D10)
						static const CCryNameR Name_g_SkinQuat("_g_SkinQuat");
						SCGBind *pBind = pCurVS->mfGetParameterBind(Name_g_SkinQuat);
						assert(pBind);
						if (pBind)
							nSlot = pBind->m_dwCBufSlot;
	#endif
						int nFirst = pChunk->m_arrChunkBoneIDs[0];
						int nLast = nFirst;
						int nOffs = 0;
						for (j=1; j<numBonesPerChunk; j++)
						{
							uint32 BoneID=pChunk->m_arrChunkBoneIDs[j];
							assert(BoneID < 0x100);
							if (BoneID != nLast+1)
							{
								FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsL, pMBGlobalSkinQuatsL);
								nFirst = BoneID;
								nOffs = j;
							}
							nLast = BoneID;
						}
						FX_FlushSkinVSParams(pCurVS, nFirst, j-nOffs, nOffs, numBonesPerChunk, nSlot, pGlobalSkinQuatsL, pMBGlobalSkinQuatsL);
					}
				}

        if (HWSkinningFlags & eHWS_ShapeDeform)
        {
#if defined (DIRECT3D9)
          pCurVS->mfParameterReg(VSCONST_SHAPEDEFORMATION, &HWShapeDeformationData[0].x, 8, eHWSC_Vertex);
#elif defined (DIRECT3D10)
					static const CCryNameR Name__g_ShapeDeformationData("_g_ShapeDeformationData");
          SCGBind *pBind = pCurVS->mfGetParameterBind(Name__g_ShapeDeformationData);
	#ifndef PS3
          assert(pBind);
	#endif
          if (pBind)
            pCurVS->mfParameterReg(VSCONST_SHAPEDEFORMATION, pBind->m_dwCBufSlot, eHWSC_Vertex, &HWShapeDeformationData[0].x, 8, VSCONST_SHAPEDEFORMATION+8);
#endif
        }
        
				if(ShouldApplyFogCorrection())
					FX_FogCorrection();

        // Unlock all VB (if needed) and set current streams
        if (FX_CommitStreams(pPass))
        {
          uint32 nObj;
          CRenderObject *pSaveObj = m_RP.m_pCurObject;
          CRenderObject *pObject = pSaveObj;
          for (nObj=0; nObj<m_RP.m_RIs[0].Num(); nObj++)
          {       
            pObject = rRP.m_RIs[0][nObj]->pObj;
            rRP.m_pCurObject = pObject;

#ifdef DO_RENDERSTATS
						if( (CV_r_stats==6 || m_pDebugRenderNode || m_bCollectDrawCallsInfo) && !(rTI.m_PersFlags & RBPF_MAKESPRITE) ) 
							FX_TrackStats(pObject, pRE->m_pRenderMesh);
#endif

#ifdef DO_RENDERLOG
            if (CRenderer::CV_r_log >= 3)
            {
              Vec3 vPos = pObject->GetTranslation();
              Logv(SRendItem::m_RecurseLevel[nThreadID], "+++ HWSkin Group Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_nNumRendPasses, pObject->m_Id, vPos[0], vPos[1], vPos[2]);
            }
#endif





            pCurVS->mfSetParametersPI(pObject, pSh);
            pCurPS->mfSetParametersPI(NULL, NULL);

#if defined(DIRECT3D10) && !defined(PS3) && !defined(CAFE)
            if (pCurGS)
              pCurGS->mfSetParametersPI(NULL, NULL);
            else
              CHWShader_D3D::mfBindGS(NULL, NULL);
#endif

            {
              //PROFILE_FRAME(Draw_ShaderIndexMesh);
              if (m_RP.m_pRE)
                m_RP.m_pRE->mfDraw(pSh, pPass);
              else
                FX_DrawIndexedMesh(eptTriangleList);
            }
          }
          m_RP.m_FlagsShader_MD &= ~(HWMD_TCM | HWMD_TCG);
          if (pSaveObj != rRP.m_pCurObject)
          {
            rRP.m_pCurObject = pSaveObj;
          }
        }
      }
    }
  }
#ifdef TESSELLATION_RENDERER
	if (bTessEnabled)
	{
		CHWShader_D3D::mfBindDS(NULL, NULL);
		CHWShader_D3D::mfBindHS(NULL, NULL);
	}
#endif
  rRP.m_RendNumGroup = -1;
}

#if defined(DO_RENDERSTATS)
void CD3D9Renderer::FX_TrackStats( CRenderObject *pObj, IRenderMesh *pRenderMesh )
{
  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;

  if( pObj )
  {
    if( IRenderNode *pRenderNode = (IRenderNode*)pObj->m_pRenderNode  )
    {
			//Add to per node map for r_stats 6
			if(CV_r_stats==6 || m_pDebugRenderNode)
			{
#if !defined(_RELEASE)
				IRenderer::RNDrawcallsMapNode& drawCallsInfoPerNode = rRP.m_pRNDrawCallsInfoPerNode[m_RP.m_nProcessThreadID];

				IRenderer::RNDrawcallsMapNodeItor pItor = drawCallsInfoPerNode.find( pRenderNode );

				if( pItor != drawCallsInfoPerNode.end() )
				{
					SDrawCallCountInfo &pInfoDP = pItor->second;
					pInfoDP.Update( pObj, pRenderMesh );
				}
				else
				{
					SDrawCallCountInfo pInfoDP;
					pInfoDP.Update( pObj, pRenderMesh );
					drawCallsInfoPerNode.insert( IRenderer::RNDrawcallsMapNodeItor::value_type( pRenderNode, pInfoDP ) );
				}
#endif
			}

			//Add to per mesh map for perfHUD / Statoscope
#if !defined(_RELEASE)
			if(m_bCollectDrawCallsInfo)
			{
				IRenderer::RNDrawcallsMapMesh& drawCallsInfoPerMesh = rRP.m_pRNDrawCallsInfoPerMesh[m_RP.m_nProcessThreadID];

				IRenderer::RNDrawcallsMapMeshItor pItor = drawCallsInfoPerMesh.find( pRenderMesh );

				if( pItor != drawCallsInfoPerMesh.end() )
				{
					SDrawCallCountInfo &pInfoDP = pItor->second;
					pInfoDP.Update( pObj, pRenderMesh );
				}
				else
				{
					SDrawCallCountInfo pInfoDP;
					pInfoDP.Update( pObj, pRenderMesh );
					drawCallsInfoPerMesh.insert( IRenderer::RNDrawcallsMapMeshItor::value_type( pRenderMesh, pInfoDP ) );
				}

			}
#endif
    }
  }
}
#endif

#ifdef TESSELLATION_RENDERER
bool CD3D9Renderer::FX_SetTessellationFlags(CHWShader_D3D *&pCurHS, CHWShader_D3D *&pCurDS, const SShaderPass * pPass)
{
	SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
	pCurHS = (CHWShader_D3D *)pPass->m_HShader;
	pCurDS = (CHWShader_D3D *)pPass->m_DShader;
	bool bTessEnabled = (pCurHS != NULL)
		&& (pCurDS != NULL)
		&& !(rRP.m_pCurObject->m_ObjFlags & FOB_NEAREST)
		&& (rRP.m_pCurObject->m_ObjFlags & FOB_ALLOW_TESSELLATION);
#ifndef MOTIONBLUR_TESSELLATION
	bTessEnabled &= !(rRP.m_PersFlags2 & RBPF2_MOTIONBLURPASS);
#endif
	if (bTessEnabled)
	{
		if (CV_r_tessellationdebug == 1)
			rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG1];
	}
	else
	{
		pCurHS = NULL;
		pCurDS = NULL;
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
	}

	return bTessEnabled;
}

void CD3D9Renderer::FX_SetAdjacencyOffsetBuffer()
{
	if (m_RP.m_pRE && m_RP.m_pRE->mfGetType() == eDATA_Mesh)
	{
		CREMeshImpl *pMesh = (CREMeshImpl*) m_RP.m_pRE;
		// this buffer contains offset HS has to apply to SV_PrimitiveID it gets from HW. we need this because
		// sometimes we do not start rendering from the beginning of index buffer
		// AI AndreyK: probably texture buffer has to be replayed by per-instance constant
		m_pd3dDeviceContext->HSSetShaderResources(15, 1, &pMesh->m_tessCB.m_pSRV);
	}
	else
	{
		ID3D11ShaderResourceView *pNULLSRV = NULL;
		m_pd3dDeviceContext->HSSetShaderResources(15, 1, &pNULLSRV);
	}
}

#endif //#ifdef TESSELLATION_RENDERER

extern int nStartRender;

void CD3D9Renderer::FX_DrawBatch(CShader *pSh, SShaderPass *pPass)
{	
  nStartRender++;









	FUNCTION_PROFILER_RENDER_FLAT
  SRenderPipeline& RESTRICT_REFERENCE rRP = m_RP;
  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];

  //if (m_RP.m_RendNumIndices != 36 || !strstr(m_RP.m_pShaderResources->m_szMaterialName, "kowloon_road"))
  //  return;
  //if (m_RP.m_RendNumIndices != 10098 && m_RP.m_RendNumIndices != 36)
  //  return;

  // Set culling mode
  if (!(rRP.m_FlagsPerFlush & RBSI_LOCKCULL))
  {
    if (pPass->m_eCull != -1)
      D3DSetCull((ECull)pPass->m_eCull);
  }
  
	ISkinnable* pCharInstance = NULL;
	if (FX_SetStreamFlags(pPass) && (rRP.m_pCurObject->m_ObjFlags & FOB_CHARACTER) && CV_r_character_nodeform != 1)
  {
		// Hardware skinning
    SRenderObjData *pOD = rRP.m_pCurObject->GetObjData(rRP.m_nProcessThreadID);
    if (!pOD || !(pCharInstance = pOD->m_pCharInstance))
    {
      Warning ("Warning: Skinned geometry used without character instance");
    }
  }
  if (pCharInstance)
  {
    FX_DrawBatchSkinned(pSh, pPass, pCharInstance);
  }
  else
  {
    PROFILE_FRAME(DrawShader_BatchStatic);

		// Set shaders
		bool bRes = true;
		bool bTessEnabled = false;
#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
		CHWShader_D3D *pCurGS = (CHWShader_D3D *)pPass->m_GShader;

		if (pCurGS)
			bRes &= pCurGS->mfSetGS(0);
		else
			CHWShader_D3D::mfBindGS(NULL, NULL);

	#ifdef TESSELLATION_RENDERER
		CHWShader_D3D *pCurHS, *pCurDS;
		bTessEnabled = FX_SetTessellationFlags(pCurHS, pCurDS, pPass);
		if (bTessEnabled)
		{
			bRes &= pCurHS->mfSetHS(0);
			bRes &= pCurDS->mfSetDS(HWSF_SETTEXTURES);
		}
		else
		{
			CHWShader_D3D::mfBindHS(NULL, NULL);
			CHWShader_D3D::mfBindDS(NULL, NULL);
		}
	#else
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
	#endif
#endif
		CHWShader_D3D *pCurVS = (CHWShader_D3D *)pPass->m_VShader;
		CHWShader_D3D *pCurPS = (CHWShader_D3D *)pPass->m_PShader;
		bRes &= pCurPS->mfSetPS(HWSF_SETTEXTURES);
		bRes &= pCurVS->mfSetVS(0);

    if (bRes)
    {
      if (ShouldApplyFogCorrection())
				FX_FogCorrection();

      assert(rRP.m_pRE || !rRP.m_nLastRE);
      CRendElementBase *pRE = rRP.m_pRE;
      CRendElementBase *pRESave = pRE;
      CRenderObject *pSaveObj = rRP.m_pCurObject;
      SRenderShaderResources *pCurRes = rRP.m_pShaderResources;
      SRenderShaderResources *pSaveRes = pCurRes;
      for (int nRE=0; nRE<=rRP.m_nLastRE; nRE++)
      {
        TArray<SRendItem *>& rRIs = rRP.m_RIs[nRE];
				if(!(rRP.m_FlagsPerFlush&RBSI_INSTANCED) || rRIs.size() <= (unsigned)CRenderer::m_iGeomInstancingThreshold)
				{
					if (pRE)
					{
						pRE = rRP.m_pRE = rRIs[0]->pElem;
#if !defined(PS3) && !defined(XENON)
//          rRIs[0]->nOcclQuery = 1000;  // Mark this batch list that it cannot be instantiated in subsequent passes
#endif
						//assert(nRE || pRE == rRP.m_pRE);
						SRenderShaderResources *pRes = (rRP.m_PersFlags2 & RBPF2_MATERIALLAYERPASS) ? rRP.m_pShaderResources : SRendItem::mfGetRes(rRIs[0]->SortVal);
						uint32 nFrameID = rTI.m_nFrameUpdateID;
						if (!pRE->mfCheckUpdate(rRP.m_CurVFormat, rRP.m_FlagsStreams_Stream | 0x80000000, nFrameID, bTessEnabled))
							continue;
						if (nRE || rRP.m_nNumRendPasses || pCurRes != pRes) // Only static meshes (CREMeshImpl) can use geom batching 
						{
							rRP.m_pShaderResources = pRes;
							pRE->mfPrepare(false);
							CREMeshImpl* pM = (CREMeshImpl*) pRE;
							if (pM->m_CustomData || pCurRes != pRes) // Custom data can indicate some shader parameters are from mesh
							{
								pCurVS->mfSetParametersPB();
								pCurPS->mfSetParametersPB();
								if (pCurPS->m_pCurInst)
									pCurPS->mfSetSamplers(pCurPS->m_pCurInst->m_pSamplers, eHWSC_Pixel);
	#ifdef TESSELLATION_RENDERER
								if (pCurDS && pCurDS->m_pCurInst)
									pCurDS->mfSetSamplers(pCurDS->m_pCurInst->m_pSamplers, eHWSC_Domain);
	#endif
								rRP.m_nCommitFlags |= FC_PER_BATCH_PARAMS | FC_MATERIAL_PARAMS;
								pCurRes = pRes;
							}
						}
					}

					rRP.m_nNumRendPasses++;

					// Unlock all VBs (if needed) and bind current streams
					if (FX_CommitStreams(pPass))
					{
						uint32 nO;
						const uint32 nNumRI = rRIs.Num();
						CRenderObject *pObj = NULL;
						SInstanceInfo *pI;

	#ifdef DO_RENDERSTATS
						if( (CV_r_stats==6 || m_pDebugRenderNode || m_bCollectDrawCallsInfo) && !(rTI.m_PersFlags & RBPF_MAKESPRITE) ) 
						{
							for (nO=0; nO<nNumRI; nO++)
							{
								pObj = rRIs[nO]->pObj;

								CRendElementBase* pElemBase = rRIs[nO]->pElem;

								if(pElemBase->mfGetType()==eDATA_Mesh)
								{
									CREMeshImpl* pMesh = (CREMeshImpl*) pElemBase;
									IRenderMesh* pRenderMesh = pMesh ? pMesh->m_pRenderMesh : NULL;

									FX_TrackStats(pObj, pRenderMesh);
								}

								//Not currently tracking other Render element types, may want to in future
								/*else
								{
								if(pObj->m_pRenderNode)
								{
								printf("Render Element 0x%p has type: %s, but has valid render node\n", pElemBase, pElemBase->mfTypeString());
								}
								}*/
							}
						}
	#endif

						for (nO=0; nO<nNumRI; ++nO)
						{
							pObj = rRIs[nO]->pObj;
							rRP.m_pCurObject = pObj;
							pI = &pObj->m_II;

							byte bStartQ = FX_StartQuery(rRIs[nO]);
							if (bStartQ == 2)
								continue;

	#ifdef DO_RENDERLOG
							if (CRenderer::CV_r_log >= 3)
							{
								Vec3 vPos = pObj->GetTranslation();
								Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "+++ General Pass %d (Obj: %d [%.3f, %.3f, %.3f], %.3f)\n", m_RP.m_nNumRendPasses, pObj->m_Id, vPos[0], vPos[1], vPos[2], pObj->m_fDistance);
							}
	#endif





							pCurVS->mfSetParametersPI(pObj, pSh);
							pCurPS->mfSetParametersPI(NULL, NULL);

			#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
							if (pCurGS)
								pCurGS->mfSetParametersPI(NULL, NULL);
							else
								CHWShader_D3D::mfBindGS(NULL, NULL);
			#endif

							{
								if (pRE)
									pRE->mfDraw(pSh, pPass);
								else
									FX_DrawIndexedMesh(eptTriangleList);
							}
							m_RP.m_nCommitFlags &= ~(FC_TARGETS | FC_GLOBAL_PARAMS);
							FX_EndQuery(rRIs[nO], bStartQ);
						}

						rRP.m_FlagsShader_MD &= ~(HWMD_TCM | HWMD_TCG);

						if(pRE)
						{
							pRE->m_Flags &= ~FCEF_PRE_DRAW_DONE;
						}
					}
					rRP.m_pCurObject = pSaveObj;
					rRP.m_pRE = pRESave;
					rRP.m_pShaderResources = pSaveRes;
				}
			}
    }
#ifdef TESSELLATION_RENDERER
		if (bTessEnabled)
		{
			CHWShader_D3D::mfBindHS(NULL, NULL);
			CHWShader_D3D::mfBindDS(NULL, NULL);
		}
#endif
  }
  m_RP.m_nCommitFlags = FC_ALL;








}

//============================================================================================

void CD3D9Renderer::FX_DrawShader_General(CShader *ef, SShaderTechnique *pTech)
{
	FUNCTION_PROFILER_RENDER_FLAT
  SShaderPass *slw;
  int32 i;

  PROFILE_FRAME(DrawShader_Generic);

  SThreadInfo& RESTRICT_REFERENCE rTI = m_RP.m_TI[m_RP.m_nProcessThreadID];

  EF_Scissor(false, 0,0,0,0);

  if (pTech->m_Passes.Num())
  {
    slw = &pTech->m_Passes[0];
    const int nCount = pTech->m_Passes.Num();
    for (i=0; i<nCount; i++, slw++)
    {    
      m_RP.m_pCurPass = slw;

      // Set all textures and HW TexGen modes for the current pass (ShadeLayer)
      assert (slw->m_VShader && slw->m_PShader);
      if (!slw->m_VShader || !slw->m_PShader)
        continue;

      if (rTI.m_PersFlags & RBPF_SHADOWGEN)
      {
        if (slw->m_eCull == eCULL_None)
          m_cEF.m_TempVecs[1][0] = rTI.m_vFrustumInfo.w;
      }

      FX_CommitStates(pTech, slw, (slw->m_PassFlags & SHPF_NOMATSTATE) == 0);

			bool bSkinned = (m_RP.m_pCurObject->m_ObjFlags & FOB_CHARACTER) && !CV_r_character_nodeform;

//#if !defined(XENON) && !defined(PS3)
      if (m_RP.m_FlagsPerFlush & RBSI_INSTANCED && !bSkinned)
      {
        // Using HW geometry instancing approach
        FX_DrawShader_InstancedHW(ef, slw);
      }
      else
//#endif
      {
        FX_DrawBatch(ef, slw);
      }
    }
  }
}

void CD3D9Renderer::FX_DrawEffectLayerPasses()
{
	if (!m_RP.m_pRootTechnique || m_RP.m_pRootTechnique->m_nTechnique[TTYPE_EFFECTLAYER] < 0)
		return;

	CShader *sh = m_RP.m_pShader;
	SShaderTechnique *pTech = m_RP.m_pShader->m_HWTechniques[m_RP.m_pRootTechnique->m_nTechnique[TTYPE_EFFECTLAYER]];

	PROFILE_FRAME(DrawShader_EffectLayerPasses);

	PROFILE_LABEL_PUSH( "EFFECT_LAYER_PASS" );

  CRendElementBase *pRE = m_RP.m_pRE;
  uint64 nSaveRT = m_RP.m_FlagsShader_RT;
  uint32 nSaveMD = m_RP.m_FlagsShader_MD;
  uint32 nSavePersFlags = m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags;
  uint32 nSavePersFlags2 = m_RP.m_PersFlags2;
  uint32 nSaveStates = m_RP.m_StateAnd;
  void *pCustomData = m_RP.m_pRE->m_CustomData;

	float fDistToCam = 500.0f;
	float fDist = CV_r_detaildistance;
  for (int nRE=0; nRE<=m_RP.m_nLastRE; nRE++)
  {
    s_tempRIs.SetUse(0);

    m_RP.m_pRE = m_RP.m_RIs[nRE][0]->pElem;

	  if (m_RP.m_pRE)
	  {
		  CRenderObject *pObj = m_RP.m_pCurObject;
		  uint32 nObj;

		  for (nObj=0; nObj<m_RP.m_RIs[nRE].Num(); nObj++)
		  {
			  pObj = m_RP.m_RIs[nRE][nObj]->pObj;
			  //float fDistObj = pObj->m_fDistance;
			  //if ( fDistObj <= fDist+4.0f ) 
				  s_tempRIs.AddElem(m_RP.m_RIs[nRE][nObj]);
		  }
	  } //
	  else
		  continue;

    if (!s_tempRIs.Num())
		  continue;
	      
    m_RP.m_pRE->mfPrepare(false);
	  bool bHDRMode = IsHDRModeEnabled();
	  bool bLinearSpaceShading = IsLinearSpaceShadingEnabled();








    int nSaveLastRE = m_RP.m_nLastRE;
    m_RP.m_nLastRE = 0;
	  TArray<SRendItem *> saveArr;
    saveArr.Assign(m_RP.m_RIs[0]);
	  m_RP.m_RIs[0].Assign(s_tempRIs);
	  CRenderObject *pSaveObject = m_RP.m_pCurObject;
	  m_RP.m_pCurObject = m_RP.m_RIs[0][0]->pObj;
	  m_RP.m_FlagsShader_MD &= ~(HWMD_TCM | HWMD_TCG);

	  Vec4 data[4];
	  m_RP.m_pRE->m_CustomData = &data[0].x;

	  SEfResTexture *rt = m_RP.m_pShaderResources->m_Textures[EFTT_CUSTOM];    

	  const float fDefaultUVTilling = 20;
    float fUScale = rt->GetTiling(0);
    float fVScale = rt->GetTiling(1);
	  if (!fUScale)	fUScale = fDefaultUVTilling;
	  if (!fVScale)	fVScale = fDefaultUVTilling;

    data[0].z = 0;
    if (rt->m_Ext.m_pTexModifier)
      data[0].z = rt->m_Ext.m_pTexModifier->m_UOscRate;
	  data[0].x = fUScale; data[0].y = fVScale;
	  if (!data[0].z)
		  data[0].z = 1.0f;

    // Flicker timming for sparks/plasma
    float fTime = m_RP.m_TI[m_RP.m_nProcessThreadID].m_RealTime;
    data[0].w = (fTime * 20.0f + fTime * 4.0f);
    data[0].w -= floorf( data[0].w );
    data[0].w = fabs( data[0].w *2.0f - 1.0f );
    data[0].w *= data[0].w;

	  int32 nMaterialStatePrevOr = m_RP.m_MaterialStateOr;
    int32 nMaterialStatePrevAnd = m_RP.m_MaterialStateAnd;
	  m_RP.m_MaterialStateAnd = GS_BLEND_MASK;
		m_RP.m_MaterialStateOr = GS_BLSRC_ONE|GS_BLDST_ONEMINUSSRCALPHA;

		m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3]|g_HWSR_MaskBit[HWSR_SAMPLE4]);

		// Set sample flags
		SRenderObjData* pRenderObjectData = m_RP.m_pCurObject->GetObjData( m_RP.m_nProcessThreadID );
		if( pRenderObjectData )
		{
			uint32 layerEffectParams = pRenderObjectData->m_pLayerEffectParams;

			// m_pLayerEffectParams "x" channel
			if(((layerEffectParams&0xff000000)>>24) > 0)
			{
				m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
				data[0].z *= CRenderer::CV_r_maxSuitPulseSpeedMultiplier;
			}

			// m_pLayerEffectParams "y" channel
			if(((layerEffectParams&0x00ff0000)>>16) > 0)
			{
				m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
				data[0].z *= CRenderer::CV_r_armourPulseSpeedMultiplier;
			}

			// m_pLayerEffectParams "w" channel
			if(((layerEffectParams&0x000000ff)) > 0)
			{
				m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
			}
		}








	  FX_DrawTechnique(sh, pTech, true);

	  m_RP.m_RIs[0].Assign(saveArr);
	  saveArr.ClearArr();

    m_RP.m_nLastRE = nSaveLastRE;
	  m_RP.m_pCurObject = pSaveObject;
	  m_RP.m_pPrevObject = NULL;
    m_RP.m_MaterialStateAnd = nMaterialStatePrevAnd;
    m_RP.m_MaterialStateOr = nMaterialStatePrevOr;
  }

  m_RP.m_pRE = pRE;

	m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags = nSavePersFlags;
	m_RP.m_PersFlags2 = nSavePersFlags2;
  m_RP.m_StateAnd = nSaveStates;
	m_RP.m_FlagsShader_RT = nSaveRT;
	m_RP.m_FlagsShader_MD = nSaveMD;
	m_RP.m_pRE->m_CustomData = pCustomData;

	PROFILE_LABEL_POP( "EFFECT_LAYER_PASS" );
}

void CD3D9Renderer::FX_DrawCausticsPasses( )
{
	if(CRenderer::CV_r_watercausticsdeferred)
		return;

  // todo: test if stencil pre-pass is worth when above water
  if( (!(m_RP.m_nRendFlags & SHDF_ALLOW_WATER) && !(m_RP.m_PersFlags2 & RBPF_MIRRORCAMERA)) || !m_RP.m_pRootTechnique || m_RP.m_pRootTechnique->m_nTechnique[TTYPE_CAUSTICS] < 0 )
    return;
  
  if( !m_RP.m_pCurObject || !m_RP.m_pShader )
    return;

  if( (m_RP.m_pCurObject->m_ObjFlags & FOB_DECAL) || (m_RP.m_pShader->m_Flags & EF_DECAL) )
    return;
  
  static int nFrameID = 0;
  static bool bOceanVolumeVisible = false;
  static ICVar *pVar = iConsole->GetCVar("e_WaterOcean");
  static bool bOceanEnabled = 0;
  static float fWatLevel = 0;
  static Vec4 pCausticsParams;

  int nCurrFrameID = m_RP.m_TI[m_RP.m_nProcessThreadID].m_nFrameID;

  // Only get 3dengine data once..
  if( nFrameID != nCurrFrameID )
  {
		N3DEngineCommon::SOceanInfo &OceanInfo= gRenDev->m_p3DEngineCommon.m_OceanInfo;
    nFrameID = nCurrFrameID;
		bOceanVolumeVisible = (OceanInfo.m_nOceanRenderFlags & OCR_OCEANVOLUME_VISIBLE) != 0;
    pCausticsParams = gEnv->p3DEngine->GetCausticsParams();
    fWatLevel = gEnv->p3DEngine->GetWaterLevel();
  }

  if( !bOceanVolumeVisible || pCausticsParams.z <= 1e-6f )
    return;

  float fDistToSectorWithWater = gEnv->p3DEngine->GetDistanceToSectorWithWater();
  if( fDistToSectorWithWater > CRenderer::CV_r_watercausticsdistance * 0.5f )
    return;

  CShader *sh = m_RP.m_pShader;
  SShaderTechnique *pTech = m_RP.m_pShader->m_HWTechniques[m_RP.m_pRootTechnique->m_nTechnique[TTYPE_CAUSTICS]];

  CRendElementBase *pRE = m_RP.m_pRE;

  PROFILE_FRAME(DrawShader_CausticsPasses);

	PROFILE_LABEL_PUSH( "CAUSTICS_PASS" );

  for (int nRE=0; nRE<=m_RP.m_nLastRE; nRE++)
  {
    s_tempRIs.SetUse(0);

    m_RP.m_pRE = m_RP.m_RIs[nRE][0]->pElem;

    Vec3 pMinStart;
    float fDistToCam = 500.0f;
    float fDist = CRenderer::CV_r_watercausticsdistance;//pCausticsParams.y;
    if (m_RP.m_pRE)
    {
      CRenderObject *pObj = NULL;
      uint32 nObj;
   
      AABB bb;
      m_RP.m_pRE->mfGetBBox(bb.min, bb.max);        
      
      Vec3 pMin, pMinOS;        
      pMinStart = bb.min;

      for (nObj=0; nObj<m_RP.m_RIs[nRE].Num(); nObj++)
      {
        pObj = m_RP.m_RIs[nRE][nObj]->pObj;
        float fDistObj = pObj->m_fDistance;
                    
        if (fDistObj <= fDist+4.0f && !(pObj->m_nMaterialLayers&MTL_LAYER_BLEND_CLOAK) ) // special case: disable caustics when cloak active
        {
          AABB bbObj = bb.CreateTransformedAABB(pObj->GetMatrix(), bb);  
          float fBBRadius = bbObj.GetRadius();

          if( m_RP.m_nPassGroupID != EFSLIST_TERRAINLAYER )
            pMin = bbObj.GetCenter();
          else  
            pMin = bbObj.min;
          
          if (pMin.z < fWatLevel )
            s_tempRIs.AddElem(m_RP.m_RIs[nRE][nObj]);
        }
      }
    }
    else
      continue;

    if (!s_tempRIs.Num())
      continue;
    
    int nSaveLastRE = m_RP.m_nLastRE;
    m_RP.m_nLastRE = 0;
    m_RP.m_pRE->mfPrepare(false);
    uint64 nSaveRT = m_RP.m_FlagsShader_RT;
  //  m_RP.m_FlagsShader_RT = 0;

    Vec4 data = Vec4(pMinStart.x, pMinStart.y, pMinStart.z, 1.0f);
    void *pCustomData = m_RP.m_pRE->m_CustomData;
    if( m_RP.m_nPassGroupID != EFSLIST_TERRAINLAYER )
      m_RP.m_pRE->m_CustomData = &data.x;

    TArray<SRendItem *> saveArr;
    saveArr.Assign(m_RP.m_RIs[0]);
    CRenderObject *pSaveObject = m_RP.m_pCurObject;

    m_RP.m_RIs[0].Assign(s_tempRIs);
    m_RP.m_pCurObject = m_RP.m_RIs[0][0]->pObj;

    int nPersFlags2Save = m_RP.m_PersFlags2;

    static int nStencilFrameID = 0;
    if( CRenderer::CV_r_watercaustics == 2 )
    { 
      if( nStencilFrameID != GetFrameID())
      {
        nStencilFrameID = GetFrameID();

        FX_ResetPipe();     
        // stencil pre-pass
        CShader *pSH( CShaderMan::m_ShaderShadowMaskGen );
        //EF_ClearBuffers(FRT_CLEAR_STENCIL|FRT_CLEAR_IMMEDIATE, NULL, 1); 

        // make box for stencil passes
        t_arrDeferredMeshIndBuff arrDeferredInds;
        t_arrDeferredMeshVertBuff arrDeferredVerts;
        CreateDeferredUnitBox(arrDeferredInds, arrDeferredVerts);

        Vec3 vCamPos = gRenDev->GetRCamera().Orig;
        float fWaterPlaneSize = gRenDev->GetCamera().GetFarPlane();

        m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView->Push();
        Matrix34 mLocal;
        mLocal.SetIdentity();
        
        mLocal.SetScale(Vec3(fDist*2, fDist*2, fWatLevel + 3.0f));//,boxOcean.max);
        mLocal.SetTranslation( Vec3(vCamPos.x-fDist, vCamPos.y-fDist, -2) );
        Matrix44 mLocalTransposed = GetTransposed44(Matrix44(mLocal));
        m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView->MultMatrixLocal(&mLocalTransposed);

        uint32 nPasses = 0;         
        static CCryNameTSCRC TechName0 = "DeferredShadowPass";
        pSH->FXSetTechnique(TechName0);
        pSH->FXBegin( &nPasses, FEF_DONTSETSTATES );
        pSH->FXBeginPass( DS_SHADOW_CULL_PASS );

        uint32 nVertOffs, nIndOffs;

        //allocate vertices
        SVF_P3F_C4B_T2F  *pVerts((SVF_P3F_C4B_T2F *)m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(arrDeferredVerts.size(), nVertOffs));
        memcpy( pVerts, &arrDeferredVerts[0], arrDeferredVerts.size()*sizeof(SVF_P3F_C4B_T2F ) );
        m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB();

        //allocate indices
        uint16 *pInds = m_DynIB.LockIB(arrDeferredInds.size(), nIndOffs);
        memcpy(pInds, &arrDeferredInds[0], sizeof(uint16)*arrDeferredInds.size());
        m_DynIB.UnlockIB();

        m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();
        m_DynIB.Bind();

        if (!FAILED(FX_SetVertexDeclaration( 0, eVF_P3F_C4B_T2F)))
          FX_StencilCullPass(-1, nVertOffs, arrDeferredVerts.size(), nIndOffs, arrDeferredInds.size());

        pSH->FXEndPass();
        pSH->FXEnd();

        m_RP.m_TI[m_RP.m_nProcessThreadID].m_matView->Pop();
      }

      FX_SetStencilState(
        STENC_FUNC(FSS_STENCFUNC_EQUAL) |
        STENCOP_FAIL(FSS_STENCOP_KEEP) |
        STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
        STENCOP_PASS(FSS_STENCOP_KEEP),
        m_nStencilMaskRef, 0xFFFFFFFF, 0xFFFFFFFF);

      //m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags2 |=RBPF2_ENABLESTENCILPB;
    }

    FX_SetStencilState(
      STENC_FUNC(FSS_STENCFUNC_EQUAL) |
      STENCOP_FAIL(FSS_STENCOP_KEEP) |
      STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
      STENCOP_PASS(FSS_STENCOP_KEEP),
      m_nStencilMaskRef, 0xFFFFFFFF, 0xFFFFFFFF);

    FX_DrawTechnique(sh, pTech, true);

    m_RP.m_RIs[0].Assign(saveArr);
    saveArr.ClearArr();

    m_RP.m_nLastRE = nSaveLastRE;
    m_RP.m_pCurObject = pSaveObject;
    m_RP.m_pPrevObject = NULL;

    m_RP.m_FlagsShader_RT = nSaveRT;  
    m_RP.m_PersFlags2 = nPersFlags2Save;

    if( m_RP.m_nPassGroupID != EFSLIST_TERRAINLAYER )
      m_RP.m_pRE->m_CustomData = pCustomData;
  }

  m_RP.m_pRE = pRE;

  PROFILE_LABEL_POP( "CAUSTICS_PASS" );
}

void CD3D9Renderer::FX_DrawDebugPasses()
{
#if !defined(XENON) && !defined(PS3)
	if (!m_RP.m_pRootTechnique || m_RP.m_pRootTechnique->m_nTechnique[TTYPE_DEBUG] < 0)
		return;

	CShader *sh = m_RP.m_pShader;
	SShaderTechnique *pTech = m_RP.m_pShader->m_HWTechniques[m_RP.m_pRootTechnique->m_nTechnique[TTYPE_DEBUG]];

	PROFILE_FRAME(DrawShader_DebugPasses);

	PROFILE_LABEL_PUSH("DEBUG_PASS");

  for (int nRE=0; nRE<=m_RP.m_nLastRE; nRE++)
  {
	  s_tempRIs.SetUse(0);

    m_RP.m_pRE = m_RP.m_RIs[nRE][0]->pElem;

	  if (!m_RP.m_pRE)
		  continue;

	  for (uint32 i=0; i<m_RP.m_RIs[nRE].Num(); i++)
		  s_tempRIs.AddElem(m_RP.m_RIs[nRE][i]);

	  if (!s_tempRIs.Num())
		  continue;
	      
    m_RP.m_pRE->mfPrepare(false);
	  uint32 nSaveMD = m_RP.m_FlagsShader_MD;

	  TArray<SRendItem *> saveArr;
	  saveArr.Assign(m_RP.m_RIs[0]);
	  m_RP.m_RIs[0].Assign(s_tempRIs);

	  CRenderObject *pSaveObject = m_RP.m_pCurObject;
	  m_RP.m_pCurObject = m_RP.m_RIs[0][0]->pObj;
	  m_RP.m_FlagsShader_MD &= ~(HWMD_TCM | HWMD_TCG);
	  int32 nMaterialStatePrevOr = m_RP.m_MaterialStateOr;
    int32 nMaterialStatePrevAnd = m_RP.m_MaterialStateAnd;
	  m_RP.m_MaterialStateAnd = GS_BLEND_MASK;
	  m_RP.m_MaterialStateOr = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;

	  FX_DrawTechnique(sh, pTech, true);

	  m_RP.m_RIs[0].Assign(saveArr);
	  saveArr.ClearArr();

	  m_RP.m_pCurObject = pSaveObject;
	  m_RP.m_pPrevObject = NULL;
	  m_RP.m_FlagsShader_MD = nSaveMD;
	  m_RP.m_MaterialStateOr = nMaterialStatePrevOr;
    m_RP.m_MaterialStateAnd = nMaterialStatePrevAnd;
  }

	PROFILE_LABEL_POP("DEBUG_PASS");
#endif
}

IMaterial *CD3D9Renderer::s_pDefaultMtl = NULL;
SShaderItem CD3D9Renderer::s_pLayerShaderItem;

SRenderShaderResources *CD3D9Renderer::s_pPrevShaderResources = NULL; 
SEfResTexture **CD3D9Renderer::s_pPrevResourceTexs = NULL;
SEfResTexture *CD3D9Renderer::s_pPrevLayerResourceTexs[EFTT_MAX];

void CD3D9Renderer::FX_SetupMultiLayers( bool bEnable )
{
  CREMeshImpl*pRE = (CREMeshImpl*) m_RP.m_pRE;
  CRenderObject *pObj =  m_RP.m_pCurObject;

  if (!pObj || !(pObj->m_nMaterialLayers&MTL_LAYER_BLEND_FROZEN) || !pRE || !m_RP.m_pShaderResources )
    return; 

  if (m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN)
    return;

	if (m_RP.m_PersFlags2 & (RBPF2_CUSTOM_RENDER_PASS|RBPF2_THERMAL_RENDERMODE_PASS|RBPF2_MOTIONBLURPASS))
		return;

  if( (SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID] > 1 && !(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_MAKESPRITE)) )
    return;

  IMaterial *pObjMat = pObj->m_pCurrMaterial;  
  if (!m_RP.m_pShaderResources || !pObjMat)
    return;

  uint32 nResourcesNoDrawFlags = m_RP.m_pShaderResources->GetMtlLayerNoDrawFlags();
  if (nResourcesNoDrawFlags & MTL_LAYER_FROZEN)
    return;

  if (pObj->m_ObjFlags & FOB_DECAL || (m_RP.m_pShader->m_Flags & EF_DECAL) )
    return;

  PROFILE_FRAME(SetupMultiLayers);

  // Verify if current mesh has valid data for layers  
	if (!s_pDefaultMtl)
		s_pDefaultMtl = gEnv->p3DEngine->GetMaterialManager()->GetDefaultLayersMaterial();

  bool bDefaultLayer = false;

  if( bEnable )
  {    
    
    m_RP.m_pReplacementShader = 0;

    CRenderChunk *pChunk = pRE->m_pChunk;
    if( !pChunk )
      return;

    // Check if chunk material has layers at all    
    IMaterial *pCurrMtl = pObjMat->GetSubMtlCount()? pObjMat->GetSubMtl( pChunk->m_nMatID ) : pObjMat; 
    if( !pCurrMtl || !s_pDefaultMtl || (pCurrMtl->GetFlags() & MTL_FLAG_NODRAW ) )
      return;

    // Atm only frozen layer supports replacing of general pass
    uint8 nMaterialLayers = ((pObj->m_nMaterialLayers&MTL_LAYER_BLEND_FROZEN)>>24)? MTL_LAYER_FROZEN : 0;

    IMaterialLayer *pDefaultLayer = const_cast< IMaterialLayer* >( s_pDefaultMtl->GetLayer( nMaterialLayers, 0 ) ); 
    IMaterialLayer *pLayer = const_cast< IMaterialLayer* >( pCurrMtl->GetLayer( nMaterialLayers, 0 ) );      
    if( !pLayer )
    {
      bDefaultLayer = true;
      pLayer = pDefaultLayer;      

      if( !pLayer )
        return;
    }    

    if( !pLayer->IsEnabled() )
      return;

    s_pLayerShaderItem = pLayer->GetShaderItem();

    // Check for valid shader
    CShader *pShader = static_cast< CShader * >(s_pLayerShaderItem.m_pShader);
    if( !pShader || !pShader->m_HWTechniques.Num() || !(pShader->m_Flags2&EF2_SUPPORTS_REPLACEBASEPASS) || !s_pLayerShaderItem.m_pShaderResources )
      return;

    // Custom textures replacement    
    s_pPrevResourceTexs = m_RP.m_pShaderResources->m_Textures;
    s_pPrevShaderResources = m_RP.m_pShaderResources; 

    // Keep layer resources and replace with resources from base shader
    for(int t = 0; t < EFTT_MAX; ++t) 
    {
      s_pPrevLayerResourceTexs[t] = ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_Textures[t];
      ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_Textures[t] = s_pPrevResourceTexs[t];
    }

    if( bDefaultLayer )
    {
      // Get opacity/alpha test values (only required for default layer, which has no information)
      ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_AlphaRef = s_pPrevShaderResources->m_AlphaRef;
      
      if( s_pPrevShaderResources->m_ResFlags & MTL_FLAG_2SIDED )
        ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_ResFlags |= MTL_FLAG_2SIDED;
      else
        ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_ResFlags &= ~MTL_FLAG_2SIDED;

      ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][3] = s_pPrevShaderResources->m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][3];
    }

    // Replace shader and resources
    m_RP.m_pShader = pShader;       
    m_RP.m_pReplacementShader = m_RP.m_pShader;
    m_RP.m_PersFlags2 |= RBPF2_MATERIALLAYERPASS;    
    m_RP.m_pShaderResources = (SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources;
  }
  else
  {
    if( s_pPrevShaderResources )
    {      
      // Restore custom resources
      m_RP.m_pReplacementShader = 0;

      for(int t = 0; t < EFTT_MAX; ++t)
      {
        ((SRenderShaderResources *)s_pLayerShaderItem.m_pShaderResources)->m_Textures[t] = s_pPrevLayerResourceTexs[t];
        s_pPrevLayerResourceTexs[t] = 0;
      }

	  m_RP.m_PersFlags2 &= ~RBPF2_MATERIALLAYERPASS;
      m_RP.m_pShaderResources = s_pPrevShaderResources;   
      s_pPrevShaderResources = 0;         

    }
  } 
}

void CD3D9Renderer::FX_DrawMultiLayers()
{
  // Verify if current mesh has valid data for layers
  CREMeshImpl* pRE = (CREMeshImpl*) m_RP.m_pRE;  
  if (!m_RP.m_pShader || !m_RP.m_pShaderResources || !m_RP.m_pCurObject->m_nMaterialLayers)
    return;

  IMaterial *pObjMat = m_RP.m_pCurObject->m_pCurrMaterial;   
  if ((SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID] > 1 && !(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_MAKESPRITE)) || !m_RP.m_pShaderResources || !pObjMat)
    return;

	if (m_RP.m_PersFlags2 & (RBPF2_CUSTOM_RENDER_PASS|RBPF2_THERMAL_RENDERMODE_PASS|RBPF2_MOTIONBLURPASS))
		return;

  CRenderChunk *pChunk = pRE->m_pChunk;
  if (!pChunk)
  {
    assert(pChunk);
    return;
  }
  
  // Check if chunk material has layers at all
  IMaterial *pDefaultMtl = gEnv->p3DEngine->GetMaterialManager()->GetDefaultLayersMaterial();
  IMaterial *pCurrMtl = pObjMat->GetSubMtlCount()? pObjMat->GetSubMtl( pChunk->m_nMatID ) : pObjMat;  
  if (!pCurrMtl || !pDefaultMtl || (pCurrMtl->GetFlags() & MTL_FLAG_NODRAW))
    return;

  uint32 nLayerCount = pDefaultMtl->GetLayerCount();
  if (!nLayerCount)
    return;

  // Start multi-layers processing
  PROFILE_FRAME(DrawShader_MultiLayers);

  if (m_LogFile)
    Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], "*** Start Multilayers processing ***\n");

  for (int nRE=0; nRE<=m_RP.m_nLastRE; nRE++)
  {
    m_RP.m_pRE = m_RP.m_RIs[nRE][0]->pElem;

    // Render all layers
    for (uint32 nCurrLayer(0); nCurrLayer < nLayerCount ; ++nCurrLayer) 
    { 
      IMaterialLayer *pLayer = const_cast< IMaterialLayer* >(pCurrMtl->GetLayer(nCurrLayer));
      IMaterialLayer *pDefaultLayer =  const_cast< IMaterialLayer* >(pDefaultMtl->GetLayer(nCurrLayer));
      bool bDefaultLayer = false;
      if(!pLayer)
      {
        // Replace with default layer
        pLayer =  pDefaultLayer;
        bDefaultLayer = true;

        if( !pLayer )
          continue;
      }

      if( !pLayer->IsEnabled() )
        continue;

      // Set/verify layer shader technique 
      SShaderItem &pCurrShaderItem = pLayer->GetShaderItem();      
      CShader *pSH = static_cast<CShader*>(pCurrShaderItem.m_pShader);      
      if( !pSH || pSH->m_HWTechniques.empty())
        continue;

      SShaderTechnique *pTech = pSH->m_HWTechniques[0];
      if(!pTech) 
      {
        continue;
      }

      // Re-create render object list, based on layer properties
      {
        s_tempRIs.SetUse(0);

        float fDistToCam = 500.0f;
        float fDist = CV_r_detaildistance;
        CRenderObject *pObj = m_RP.m_pCurObject;
        uint32 nObj = 0;

        for (nObj=0; nObj<m_RP.m_RIs[nRE].Num(); nObj++)
        {
          pObj = m_RP.m_RIs[nRE][nObj]->pObj;
          uint8 nMaterialLayers = 0;
          nMaterialLayers |= ((pObj->m_nMaterialLayers&MTL_LAYER_BLEND_DYNAMICFROZEN))? MTL_LAYER_FROZEN : 0;
          nMaterialLayers |= ((pObj->m_nMaterialLayers&MTL_LAYER_BLEND_CLOAK)>>8)? MTL_LAYER_CLOAK : 0;

          if ( nMaterialLayers & (1<<nCurrLayer) )   
            s_tempRIs.AddElem(m_RP.m_RIs[nRE][nObj]); 
        }

        // nothing in render list
        if( !s_tempRIs.Num() )
          continue;
      }

      SShaderItem &pMtlShaderItem = pCurrMtl->GetShaderItem();    
      int nSaveLastRE = m_RP.m_nLastRE;
      m_RP.m_nLastRE = 0;

      SEfResTexture **pResourceTexs = ((SRenderShaderResources *)pCurrShaderItem.m_pShaderResources)->m_Textures;
      SEfResTexture *pPrevLayerResourceTexs[EFTT_MAX];

      if( bDefaultLayer )
      {
        // Keep layer resources and replace with resources from base shader
        for(int t = 0; t < EFTT_MAX; ++t) 
        {
          pPrevLayerResourceTexs[t] = ((SRenderShaderResources *)pCurrShaderItem.m_pShaderResources)->m_Textures[t];
          ((SRenderShaderResources *)pCurrShaderItem.m_pShaderResources)->m_Textures[t] = m_RP.m_pShaderResources->m_Textures[t];
        }
      }

      m_RP.m_pRE->mfPrepare(false);

      // Store current rendering data
      TArray<SRendItem *> pPrevRenderObjLst;
      pPrevRenderObjLst.Assign(m_RP.m_RIs[0]);
      CRenderObject *pPrevObject = m_RP.m_pCurObject;
      SRenderShaderResources *pPrevShaderResources = m_RP.m_pShaderResources;      
      CShader *pPrevSH = m_RP.m_pShader;
      uint32 nPrevNumRendPasses = m_RP.m_nNumRendPasses;
      uint64 nFlagsShaderRTprev = m_RP.m_FlagsShader_RT;

      SShaderTechnique *pPrevRootTech = m_RP.m_pRootTechnique;
      m_RP.m_pRootTechnique = pTech;

      bool bFirstPassPrev = m_RP.m_bFirstPass;
      int nMaterialStatePrevOr = m_RP.m_MaterialStateOr;
      int nMaterialStatePrevAnd = m_RP.m_MaterialStateAnd;
      uint32 nFlagsShaderLTprev = m_RP.m_FlagsShader_LT;
      int nCurLightPass = m_RP.m_nCurLightPass;

      int nPersFlagsPrev = m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags;
      int nPersFlags2Prev = m_RP.m_PersFlags2;
      int nMaterialAlphaRefPrev = m_RP.m_MaterialAlphaRef;
      short nLightGroupPrev = m_RP.m_nCurLightGroup;
      bool bIgnoreObjectAlpha = m_RP.m_bIgnoreObjectAlpha;
      m_RP.m_bIgnoreObjectAlpha = true;

      m_RP.m_pShader = pSH;
      m_RP.m_RIs[0].Assign(s_tempRIs);
      m_RP.m_pCurObject = m_RP.m_RIs[0][0]->pObj;
      m_RP.m_pPrevObject = NULL;
      m_RP.m_pShaderResources = (SRenderShaderResources *)pCurrShaderItem.m_pShaderResources;

      // Reset light passes (need ambient)
      m_RP.m_nNumRendPasses = 0;
      m_RP.m_nCurLightGroup = 0;
      m_RP.m_PersFlags2 |= RBPF2_MATERIALLAYERPASS;    

      if( (1<<nCurrLayer) & MTL_LAYER_FROZEN )
      {
        m_RP.m_MaterialStateAnd = GS_BLEND_MASK | GS_ALPHATEST_MASK;
        m_RP.m_MaterialStateOr  = GS_BLSRC_ONE | GS_BLDST_ONE;
        m_RP.m_MaterialAlphaRef = 0xff;
      }

      m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE4];

		  FX_DrawTechnique(pSH, pTech, false);       

      // Restore previous rendering data
      m_RP.m_RIs[0].Assign(pPrevRenderObjLst);
      pPrevRenderObjLst.ClearArr();
      m_RP.m_pShader = pPrevSH;
      m_RP.m_pShaderResources = pPrevShaderResources;
      m_RP.m_pCurObject = pPrevObject;
      m_RP.m_pPrevObject = NULL;
      m_RP.m_PersFlags2 = nPersFlags2Prev; 
      m_RP.m_nLastRE = nSaveLastRE;


      m_RP.m_nNumRendPasses = nPrevNumRendPasses;

      m_RP.m_bFirstPass = bFirstPassPrev;
      m_RP.m_FlagsShader_LT = nFlagsShaderLTprev;
      m_RP.m_nCurLightPass = nCurLightPass;
      m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags = nPersFlagsPrev;
      m_RP.m_FlagsShader_RT = nFlagsShaderRTprev;

      m_RP.m_nNumRendPasses = 0;
      m_RP.m_nCurLightGroup = nLightGroupPrev;

      m_RP.m_pRootTechnique = pPrevRootTech;
      m_RP.m_bIgnoreObjectAlpha = bIgnoreObjectAlpha;
      m_RP.m_MaterialStateOr = nMaterialStatePrevOr;
      m_RP.m_MaterialStateAnd = nMaterialStatePrevAnd;
      m_RP.m_MaterialAlphaRef = nMaterialAlphaRefPrev;

      if( bDefaultLayer )
      {
        for(int t = 0; t < EFTT_MAX; ++t)
        {
          ((SRenderShaderResources *)pCurrShaderItem.m_pShaderResources)->m_Textures[t] = pPrevLayerResourceTexs[t];
          pPrevLayerResourceTexs[t] = 0;
        }
      }

      //break; // only 1 layer allowed
    } 
  }

  m_RP.m_pRE = pRE;

  if (m_LogFile)
    Logv(SRendItem::m_RecurseLevel[m_RP.m_nProcessThreadID], "*** End Multilayers processing ***\n");
}

void CD3D9Renderer::FX_SelectTechnique(CShader *pShader, SShaderTechnique *pTech)
{
  SShaderTechniqueStat Stat;
  Stat.pTech = pTech;
  Stat.pShader = pShader;
  if (pTech->m_Passes.Num())
  {
    SShaderPass *pPass = &pTech->m_Passes[0];
    if (pPass->m_PShader && pPass->m_VShader)
    {
      Stat.pVS = (CHWShader_D3D *)pPass->m_VShader;
      Stat.pPS = (CHWShader_D3D *)pPass->m_PShader;
      Stat.pVSInst = Stat.pVS->m_pCurInst;
      Stat.pPSInst = Stat.pPS->m_pCurInst;
      g_SelectedTechs.push_back(Stat);
    }
  }
}

void CD3D9Renderer::FX_DrawTechnique(CShader *ef, SShaderTechnique *pTech, bool bGeneral)
{
	FUNCTION_PROFILER_RENDER_FLAT
  switch(ef->m_eSHDType)
  {
  case eSHDT_General:
    FX_DrawShader_General(ef, pTech);
    break;
  case eSHDT_Light:
	case eSHDT_Terrain:
    if (bGeneral)
      FX_DrawShader_General(ef, pTech);
    else
      FX_DrawMultiLightPasses(ef, pTech, 0);
    break;
  case eSHDT_Fur:
    break;
  case eSHDT_CustomDraw:
  case eSHDT_Sky:
    if (m_RP.m_pRE) 
    {
      EF_Scissor(false, 0, 0, 0, 0);
      if (pTech && pTech->m_Passes.Num())
        m_RP.m_pRE->mfDraw(ef, &pTech->m_Passes[0]);
      else
        m_RP.m_pRE->mfDraw(ef, NULL);
    }
    break;
  default:
    assert(0);
  }
  if (m_RP.m_ObjFlags & FOB_SELECTED)
    FX_SelectTechnique(ef, pTech);
}

#if defined(HW_INSTANCING_ENABLED)
static void sDetectInstancing(CShader *pShader, CRenderObject *pObj)
{
  CRenderer *rd = gRenDev;
  SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;
  if (!CRenderer::CV_r_geominstancing || rd->m_bUseGPUFriendlyBatching[rRP.m_nProcessThreadID] || !(pShader->m_Flags & EF_SUPPORTSINSTANCING) || CRenderer::CV_r_measureoverdraw ||
			// don't instance in motion blur pass or post 3d render
			rRP.m_PersFlags2 & RBPF2_MOTIONBLURPASS || rRP.m_PersFlags2 & RBPF2_POST_3D_RENDERER_PASS ||
			// only instance meshes
			!rRP.m_pRE || rRP.m_pRE->mfGetType() != eDATA_Mesh
		)
  {
    rRP.m_FlagsPerFlush &= ~RBSI_INSTANCED;
    return;
  }

  int i=0, nLastRE = rRP.m_nLastRE;
  for(; i<=nLastRE; i++)
  {
		int nRIs = rRP.m_RIs[i].Num();

		// instance even with conditional rendering - && RIs[0]->nOcclQuery<0
    if (nRIs>CRenderer::m_iGeomInstancingThreshold || (rRP.m_FlagsPerFlush & RBSI_INSTANCED))
    {
      rRP.m_FlagsPerFlush |= RBSI_INSTANCED;
      break;
    }
  }
  if (i > rRP.m_nLastRE)
    rRP.m_FlagsPerFlush &= ~RBSI_INSTANCED;
}
#endif

// Set/Restore shader resources overrided states
bool CD3D9Renderer::FX_SetResourcesState()
{
	FUNCTION_PROFILER_RENDER_FLAT
  if (!m_RP.m_pShader)
    return false;
  m_RP.m_MaterialStateOr = 0;
  m_RP.m_MaterialStateAnd = 0;
	if (!m_RP.m_pShaderResources)
		return true;
	
	PrefetchLine(m_RP.m_pShaderResources, 0);		//Shader Resources fit in a cache line, but they're not 128-byte aligned! We are likely going 
	PrefetchLine(m_RP.m_pShaderResources, 124);	//	to cache miss on access to m_ResFlags but will hopefully avoid later ones

  if (m_RP.m_pShader->m_Flags2 & EF2_IGNORERESOURCESTATES)
    return true;

	m_RP.m_ShaderTexResources[EFTT_DECAL_OVERLAY] = NULL;

  const SRenderShaderResources *pRes = m_RP.m_pShaderResources;
	const uint32 uResFlags = pRes->m_ResFlags;
  if (uResFlags & MTL_FLAG_NOTINSTANCED)
    m_RP.m_FlagsPerFlush &= ~RBSI_INSTANCED;

  bool bRes = true;
  if (uResFlags & MTL_FLAG_2SIDED)
  {
    D3DSetCull(eCULL_None);
    m_RP.m_FlagsPerFlush |= RBSI_LOCKCULL;    
  }

  if (pRes->m_AlphaRef)
  {
    if (!(m_RP.m_PersFlags2 & RBPF2_NOALPHATEST))
    {
      int nAlphaRef = (int)(pRes->m_AlphaRef*255.0f);
      m_RP.m_MaterialAlphaRef = nAlphaRef;
      m_RP.m_MaterialStateOr = GS_ALPHATEST_GEQUAL | GS_DEPTHWRITE;
      m_RP.m_MaterialStateAnd = GS_ALPHATEST_MASK;
    }
    else
      m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_ALPHATEST];
  }

  float fOpacity;
  if ((fOpacity=((SRenderShaderResources *)pRes)->Opacity()) != 1.0f)
  {
    if (!(m_RP.m_PersFlags2 & RBPF2_NOALPHABLEND))
    {
      m_RP.m_MaterialStateAnd |= GS_DEPTHWRITE | GS_BLEND_MASK;
			m_RP.m_MaterialStateOr &= ~GS_DEPTHWRITE;
      if (uResFlags & MTL_FLAG_ADDITIVE)
      {
        m_RP.m_MaterialStateOr |= GS_BLSRC_ONE | GS_BLDST_ONE;
        m_RP.m_CurGlobalColor[0] = fOpacity;
        m_RP.m_CurGlobalColor[1] = fOpacity;
        m_RP.m_CurGlobalColor[2] = fOpacity;
      }
      else
      {
        m_RP.m_MaterialStateOr |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
        m_RP.m_CurGlobalColor[3] = fOpacity;
      }
      m_RP.m_fCurOpacity = fOpacity;
    }
  }
  // Specific condition for cloak transition
  if ((m_RP.m_pCurObject->m_nMaterialLayers & MTL_LAYER_BLEND_CLOAK) && !m_RP.m_bIgnoreObjectAlpha)
  {
    uint32 nResourcesNoDrawFlags = pRes->GetMtlLayerNoDrawFlags();
    if (!(nResourcesNoDrawFlags & MTL_LAYER_CLOAK))
    {
      const float fCloakMinThreshold = 0.85f;
      if ((((m_RP.m_pCurObject->m_nMaterialLayers & MTL_LAYER_BLEND_CLOAK)>>8) / 255.0f) > fCloakMinThreshold)
      {
        m_RP.m_MaterialStateAnd |= GS_BLEND_MASK; 
		m_RP.m_MaterialStateOr  |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
//#if !defined(PS3)
		m_RP.m_MaterialStateOr  |= (!IsCustomRenderModeEnabled( eRMF_NIGHTVISION )? GS_DEPTHWRITE: 0);
//#else
		// force no depth writes on ps3 for cloak 
		//	- since we using depth buffer directly, if written into it, will update depth and any technique using depth might look wrong (motion blur, dof, dof, etc)
//		m_RP.m_MaterialStateAnd |= GS_BLEND_MASK|GS_DEPTHWRITE; 
//endif
	  }
    }
  }
  
  if (!(m_RP.m_TI[m_RP.m_nProcessThreadID].m_PersFlags & RBPF_MAKESPRITE))
  {
    if (pRes->m_pDeformInfo)
      m_RP.m_FlagsShader_MDV |= pRes->m_pDeformInfo->m_eType;
    m_RP.m_FlagsShader_MDV |= m_RP.m_pCurObject->m_nMDV | m_RP.m_pShader->m_nMDV;
    if (m_RP.m_ObjFlags & FOB_OWNER_GEOMETRY)
      m_RP.m_FlagsShader_MDV &= ~MDV_DEPTH_OFFSET;
  }

  return true;
}

//===================================================================================================

static void sBatchStats(SRenderPipeline& rRP)
{
#ifndef _RELEASE
  SPipeStat& rPS = rRP.m_PS[rRP.m_nProcessThreadID];
  rPS.m_NumRendMaterialBatches++;
  rPS.m_NumRendGeomBatches += rRP.m_nLastRE+1;
  for (int i=0; i<=rRP.m_nLastRE; i++)
  {
    rPS.m_NumRendInstances += rRP.m_RIs[i].Num();
  }
#endif
}

static void sLogFlush(const char *str, CShader *pSH, SShaderTechnique *pTech)
{
  CD3D9Renderer *const __restrict rd = gcpRendD3D;
  if (rd->m_LogFile)
  {
    SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;
    if (CRenderer::CV_r_log == 4 && rRP.m_DynLMask)
    {
      uint32 nAffectMask = rRP.m_nCurLightGroup < 0 ? -1 : (0xf << (rRP.m_nCurLightGroup*4));
      uint32 nMask = (rRP.m_DynLMask & nAffectMask);
      for (uint32 n=0; n<rRP.m_DLights[rRP.m_nProcessThreadID][SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID]-1].Num(); n++)
      {
        SRenderLight *dl = &rRP.m_DLights[rRP.m_nProcessThreadID][SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID]-1][n];
        if (nMask & (1<<n))
          rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "   Light %d (\"%s\")\n", n, dl->m_sName ? dl->m_sName : "<Unknown>");
      }
    }
    rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "%s: '%s.%s', Id:%d, ResId:%d, Obj:%d, VF:%d\n", str, pSH->GetName(), pTech?pTech->m_NameStr.c_str():"Unknown", pSH->GetID(), rRP.m_pShaderResources ? rRP.m_pShaderResources->m_Id : -1, rRP.m_pCurObject->m_Id, pSH->m_eVertexFormat);
    if (rRP.m_ObjFlags & FOB_SELECTED)
    {
      if (rRP.m_MaterialStateOr & GS_ALPHATEST_MASK)
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  %.3f, %.3f, %.3f (0x%x), LM: %d, (AT) (Selected)\n", rRP.m_pCurObject->m_II.m_Matrix(0,3), rRP.m_pCurObject->m_II.m_Matrix(1,3), rRP.m_pCurObject->m_II.m_Matrix(2,3), rRP.m_pCurObject->m_ObjFlags, rRP.m_DynLMask);
      else
      if (rRP.m_MaterialStateOr & GS_BLEND_MASK)
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  %.3f, %.3f, %.3f (0x%x) (AB), LM: %d (Dist: %.3f) (Selected)\n", rRP.m_pCurObject->m_II.m_Matrix(0,3), rRP.m_pCurObject->m_II.m_Matrix(1,3), rRP.m_pCurObject->m_II.m_Matrix(2,3), rRP.m_pCurObject->m_ObjFlags, rRP.m_DynLMask, rRP.m_pCurObject->m_fDistance);
      else
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  %.3f, %.3f, %.3f (0x%x), RE: 0x%x, LM: 0x%x (Selected)\n", rRP.m_pCurObject->m_II.m_Matrix(0,3), rRP.m_pCurObject->m_II.m_Matrix(1,3), rRP.m_pCurObject->m_II.m_Matrix(2,3), rRP.m_pCurObject->m_ObjFlags, rRP.m_pRE, rRP.m_DynLMask);
    }
    else
    {
      if (rRP.m_MaterialStateOr & GS_ALPHATEST_MASK)
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  %.3f, %.3f, %.3f (0x%x) (AT), Inst: %d, RE: 0x%x, LM: %d (Dist: %.3f)\n", rRP.m_pCurObject->m_II.m_Matrix(0,3), rRP.m_pCurObject->m_II.m_Matrix(1,3), rRP.m_pCurObject->m_II.m_Matrix(2,3), rRP.m_pCurObject->m_ObjFlags, rRP.m_RIs[0].Num(), rRP.m_pRE, rRP.m_DynLMask, rRP.m_pCurObject->m_fDistance);
      else
      if (rRP.m_MaterialStateOr & GS_BLEND_MASK)
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  %.3f, %.3f, %.3f (0x%x) (AB), Inst: %d, RE: 0x%x, LM: %d (Dist: %.3f)\n", rRP.m_pCurObject->m_II.m_Matrix(0,3), rRP.m_pCurObject->m_II.m_Matrix(1,3), rRP.m_pCurObject->m_II.m_Matrix(2,3), rRP.m_pCurObject->m_ObjFlags, rRP.m_RIs[0].Num(), rRP.m_pRE, rRP.m_DynLMask, rRP.m_pCurObject->m_fDistance);
      else
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  %.3f, %.3f, %.3f (0x%x), Inst: %d, RE: 0x%x, LM: 0x%x\n", rRP.m_pCurObject->m_II.m_Matrix(0,3), rRP.m_pCurObject->m_II.m_Matrix(1,3), rRP.m_pCurObject->m_II.m_Matrix(2,3), rRP.m_pCurObject->m_ObjFlags, rRP.m_RIs[0].Num(), rRP.m_pRE, rRP.m_DynLMask);
    }
    if (rRP.m_pRE && rRP.m_pRE->mfGetType() == eDATA_Mesh)
    {
      CREMeshImpl* pRE = (CREMeshImpl*) rRP.m_pRE;
      CRenderMesh *pRM = pRE->m_pRenderMesh;
      if (pRM && pRM->m_Chunks.size() && pRM->m_sSource)
      {
        int nChunk = -1;
        for (uint32 i=0; i<pRM->m_Chunks.size(); i++)
        {
          CRenderChunk *pCH = &pRM->m_Chunks[i];
          if (pCH->pRE == pRE)
          {
            nChunk = i;
            break;
          }
        }
        rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "  Mesh: %s (Chunk: %d)\n", pRM->m_sSource, nChunk);
      }
    }
  }
}

void CD3D9Renderer::FX_RefractionPartialResolve()
{
	CD3D9Renderer *const __restrict rd = gcpRendD3D;
	SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;

	{
		int nThreadID = rRP.m_nProcessThreadID;
		SRenderObjData * ObjData = rRP.m_pCurObject->GetObjData(nThreadID);

		if( ObjData)
		{
			uint8 screenBounds[4];

			screenBounds[0] = ObjData->m_screenBounds[0];
			screenBounds[1] = ObjData->m_screenBounds[1];
			screenBounds[2] = ObjData->m_screenBounds[2];
			screenBounds[3] = ObjData->m_screenBounds[3];

			if( ((screenBounds[2] - screenBounds[0]) && (screenBounds[3] - screenBounds[1])) &&
					!( (rRP.m_nCurrResolveBounds[0] == screenBounds[0] )
					&& (rRP.m_nCurrResolveBounds[1] == screenBounds[1] )
					&& (rRP.m_nCurrResolveBounds[2] == screenBounds[2] )
					&& (rRP.m_nCurrResolveBounds[3] == screenBounds[3] )))
			{

				rRP.m_nCurrResolveBounds[0] = screenBounds[0];
				rRP.m_nCurrResolveBounds[1] = screenBounds[1];
				rRP.m_nCurrResolveBounds[2] = screenBounds[2];
				rRP.m_nCurrResolveBounds[3] = screenBounds[3];











				int currScissorX, currScissorY, currScissorW, currScissorH;
				int newScissorX = (screenBounds[0] <<4);
				int newScissorY = (screenBounds[1] <<4);
				int newScissorW = max(0, min((screenBounds[2] <<4), GetWidth()) - newScissorX);
				int newScissorH = max(0, min((screenBounds[3] <<4), GetHeight()) - newScissorY);

				CTexture * pTarget = 	CTexture::s_ptexCurrSceneTarget;

				//cache RP states  - Probably a bit excessive, but want to be safe
				SRenderShaderResources * currRes = rd->m_RP.m_pShaderResources;
				CShader * currShader  = rd->m_RP.m_pShader;
				int currShaderTechnique = rd->m_RP.m_nShaderTechnique;
				SShaderTechnique * currTechnique = rd->m_RP.m_pCurTechnique;
				uint32 currCommitFlags = rd->m_RP.m_nCommitFlags;
				uint32 currFlagsShaderBegin = rd->m_RP.m_nFlagsShaderBegin;
				ECull currCull = m_RP.m_eCull;

				float currVPMinZ = rd->m_NewViewport.fMinZ; // Todo: Add to GetViewport / SetViewport
				float currVPMaxZ = rd->m_NewViewport.fMaxZ;

				D3DSetCull(eCULL_None);
					
				bool bScissored = EF_GetScissorState(currScissorX, currScissorY, currScissorW, currScissorH);
				EF_Scissor(true, newScissorX, newScissorY, newScissorW, newScissorH);

				FX_ScreenStretchRect(pTarget);

				EF_Scissor(bScissored, currScissorX, currScissorY, currScissorW, currScissorH);

				D3DSetCull(currCull);

				//restore RP states 
				rd->m_RP.m_pShaderResources = currRes;
				rd->m_RP.m_pShader = currShader;
				rd->m_RP.m_nShaderTechnique = currShaderTechnique;
				rd->m_RP.m_pCurTechnique = currTechnique;
				rd->m_RP.m_nCommitFlags = currCommitFlags | FC_MATERIAL_PARAMS;
				rd->m_RP.m_nFlagsShaderBegin = currFlagsShaderBegin;
				rd->m_NewViewport.fMaxZ = currVPMinZ;
				rd->m_NewViewport.fMaxZ = currVPMaxZ;

			}
		}
	}
}

// Flush current render item
void CD3D9Renderer::FX_FlushShader_General()
{
	FUNCTION_PROFILER_RENDER_FLAT
  CD3D9Renderer *const __restrict rd = gcpRendD3D;
	SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;
	if (!rRP.m_pRE && !rRP.m_RendNumVerts)
		return;

	CShader *ef = rRP.m_pShader;
	if (!ef ) 
		return;















  // don't do motion vector generation or reflections on refractive objects.
  // Need to check here since refractive and transparent lists are combined for sorting.
  if( rRP.m_nPassGroupID == EFSLIST_TRANSP
	    && rRP.m_pCurObject->m_ObjFlags & FOB_REQUIRES_RESOLVE
	    && (rRP.m_PersFlags2 & RBPF2_MOTIONBLURPASS || (SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID]-1)))
  {
    return;
  }


	// update dynamic texture sources based on a shared RT only 
	const SRenderShaderResources* rsr = rRP.m_pShaderResources;
	if (rsr)
	{
		const SEfResTexture* pDiffuse = rsr->GetTexture(EFTT_DIFFUSE);
		if (pDiffuse)
		{
			IDynTextureSourceImpl* pDynTexSrc = (IDynTextureSourceImpl*) pDiffuse->m_Sampler.m_pDynTexSource;
			if (pDynTexSrc)
			{
				if (pDynTexSrc->GetSourceType() == IDynTextureSource::DTS_I_FLASHPLAYER || pDynTexSrc->GetSourceType() == IDynTextureSource::DTS_I_UIELEMENT)
				{
					if (rRP.m_PersFlags2 & RBPF2_MOTIONBLURPASS)
						return; // explicitly disable motion blur pass for flash assets

					if (rRP.m_nBatchFilter & (FB_GENERAL | FB_TRANSPARENT))
					{
						// save pipeline state
						SRenderPipeline& rp = gcpRendD3D->m_RP; // !!! don't use rRP as it's taken from rd (__restrict); the compiler will optimize the save/restore instructions !!!
						CShader* const pPrevShader = rp.m_pShader;
						const int prevShaderTechnique = rp.m_nShaderTechnique;
						SRenderShaderResources* const prevShaderResources = rp.m_pShaderResources;
						SShaderTechnique* const prevCurTechnique = rp.m_pCurTechnique;
						const uint32 prevCommitFlags = rp.m_nCommitFlags;
						const uint32 prevFlagsShaderBegin = rp.m_nFlagsShaderBegin;

						pDynTexSrc->Update(0.0f);

						// restore pipeline state
						rp.m_pShader = pPrevShader;
						rp.m_nShaderTechnique = prevShaderTechnique;
						rp.m_pShaderResources = prevShaderResources;
						rp.m_pCurTechnique = prevCurTechnique;
						rp.m_nCommitFlags = prevCommitFlags;
						rp.m_nFlagsShaderBegin = prevFlagsShaderBegin;
						gcpRendD3D->m_CurViewport.fMaxZ = -1;
					}
				}
			}
		}
	}

  // Shader overriding with layer
  if ((rRP.m_nBatchFilter & FB_GENERAL) && CV_r_usemateriallayers)
	{
    rd->FX_SetupMultiLayers(true);
		ef = rRP.m_pShader;
	}


  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];
  assert(!(rTI.m_PersFlags & RBPF_SHADOWGEN));
  assert(!(rRP.m_nBatchFilter & FB_Z));
	//leave out for ps3 since it costs too much
#if !defined(PS3) && !defined(XENON)
  if (!rRP.m_sExcludeShader.empty())
  {
		char nm[1024];
    strcpy(nm, ef->GetName());
    strlwr(nm);
    if (strstr(rRP.m_sExcludeShader.c_str(), nm))
      return;
  }
#endif//PS3
#ifdef DO_RENDERLOG
  if (rd->m_LogFile && CV_r_log == 3)
    rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n\n.. Start %s flush: '%s' ..\n", "General", ef->GetName() ? ef->GetName() : "");
#endif

#ifndef _RELEASE
  sBatchStats(rRP);
#endif
  CRenderObject *pObj = rRP.m_pCurObject;

  PROFILE_SHADER_START

  if (rd->m_RP.m_pRE)
    rd->m_RP.m_pRE = rd->m_RP.m_RIs[0][0]->pElem;

#if defined(HW_INSTANCING_ENABLED)
  sDetectInstancing(ef, pObj);
#endif

  // Techniques draw cycle...
  SShaderTechnique *__restrict pTech = ef->mfGetStartTechnique(rRP.m_nShaderTechnique);

  if (pTech)
  {
		uint32 flags = (FB_GLOW | FB_CUSTOM_RENDER | FB_MOTIONBLUR | FB_SCATTER | FB_SOFTALPHATEST);

    if (rRP.m_pShaderResources && !(rRP.m_nBatchFilter & flags))
    {
      uint32 i;
      // Update render targets if necessary
      if (!(rTI.m_PersFlags & RBPF_DRAWTOTEXTURE))
      {
				uint32 targetNum = rRP.m_pShaderResources->m_RTargets.Num();
				const SRenderShaderResources *const __restrict pShaderResources = rRP.m_pShaderResources;
        for (i=0; i<targetNum; ++i)
        {
          SHRenderTarget *pTarg = pShaderResources->m_RTargets[i];
          if (pTarg->m_eOrder == eRO_PreDraw)
            rd->FX_DrawToRenderTarget(ef, rRP.m_pShaderResources, pObj, pTech, pTarg, 0, rRP.m_pRE);
        }
				targetNum = pTech->m_RTargets.Num();
        for (i=0; i<targetNum; ++i)
        {
          SHRenderTarget *pTarg = pTech->m_RTargets[i];
          if (pTarg->m_eOrder == eRO_PreDraw)
            rd->FX_DrawToRenderTarget(ef, rRP.m_pShaderResources, pObj, pTech, pTarg, 0, rRP.m_pRE);
        }
      }
    }
    rRP.m_pRootTechnique = pTech;





    bool bGeneral = false;
		flags = (FB_GLOW | FB_MOTIONBLUR | FB_CUSTOM_RENDER | FB_SOFTALPHATEST | FB_DEBUG);

		if (rRP.m_nBatchFilter & flags)
    {
      bGeneral = true;
			int nTech = -1;
			if (rRP.m_nBatchFilter & FB_GLOW) nTech = TTYPE_GLOWPASS;
			else if (rRP.m_nBatchFilter & FB_MOTIONBLUR) nTech = TTYPE_MOTIONBLURPASS;
			else if (rRP.m_nBatchFilter & FB_CUSTOM_RENDER) nTech = TTYPE_CUSTOMRENDERPASS;
			else if (rRP.m_nBatchFilter & FB_SOFTALPHATEST) nTech = TTYPE_SOFTALPHATESTPASS;
#if !defined(XENON) && !defined(PS3)
			else if (rRP.m_nBatchFilter & FB_DEBUG) nTech = TTYPE_DEBUG;
#endif

			if (nTech >= 0 && pTech->m_nTechnique[nTech] > 0)
			{
				assert(pTech->m_nTechnique[nTech] < (int)ef->m_HWTechniques.Num());
				pTech = ef->m_HWTechniques[pTech->m_nTechnique[nTech]];
			}
    }
#ifndef _RELEASE
		if (CV_r_debugrendermode)
		{
			if (CV_r_debugrendermode & 1)
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG0];
			if (CV_r_debugrendermode & 2)
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG1];
			if (CV_r_debugrendermode & 4)
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG2];
			if (CV_r_debugrendermode & 8)
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG3];
		}
#endif
    if (!rd->FX_SetResourcesState())
    {
      if (rRP.m_pReplacementShader)
        rd->FX_SetupMultiLayers(false); 
      return;
    }

    if (rRP.m_nBatchFilter & FB_SCATTER)
    {
      if (pTech->m_nTechnique[TTYPE_SCATTERPASS] > 0)
      {
        assert(pTech->m_nTechnique[TTYPE_SCATTERPASS] < (int)ef->m_HWTechniques.Num());
        pTech = ef->m_HWTechniques[pTech->m_nTechnique[TTYPE_SCATTERPASS]];

        bGeneral = true;

        //overwrite cull mode
        if (rRP.m_PersFlags2 & RBPF2_SCATTERPASS)
          rd->D3DSetCull(eCULL_Back);
        else
          rd->D3DSetCull(eCULL_Front);

        rRP.m_FlagsPerFlush |= RBSI_LOCKCULL;
      }
      else
      {
        //TOFIX: uncomment for having proper scattering accumulation
        //////////////////////////////////////////////////////////////////////////
        //test for occluders(skeleton) rendering
        //////////////////////////////////////////////////////////////////////////
        /*if (pTech->m_nTechnique[TTYPE_Z] > 0)
        {
          assert(pTech->m_nTechnique[TTYPE_Z] < (int)ef->m_HWTechniques.Num());
          pTech = ef->m_HWTechniques[pTech->m_nTechnique[TTYPE_Z]];

          bGeneral = true;
        }*/
        //////////////////////////////////////////////////////////////////////////

				if (!(rRP.m_PersFlags2 & RBPF2_SCATTERPASS))
          return;
      }
    }

		if(rTI.m_PersFlags & RBPF_MAKESPRITE)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SPRITE];
		else if (rRP.m_ObjFlags & FOB_BENDED)
      rRP.m_FlagsShader_MDV |= MDV_BENDING;
    rRP.m_FlagsShader_RT |= pObj->m_nRTMask;
    if (rRP.m_RIs[0].Num()<=1 && !(rRP.m_ObjFlags & FOB_TRANS_MASK))
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_OBJ_IDENTITY];
	#ifdef TESSELLATION_RENDERER
    if ((pObj->m_ObjFlags & FOB_NEAREST) || !(pObj->m_ObjFlags & FOB_ALLOW_TESSELLATION))
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
	#endif
		if (!(rRP.m_PersFlags2 & RBPF2_NOSHADERFOG) && rTI.m_FS.m_bEnable && !(rRP.m_ObjFlags & FOB_NO_FOG) || !(rRP.m_PersFlags2 & RBPF2_ALLOW_DEFERREDSHADING))
    {
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_FOG];
    }

		SRenderObjData *const __restrict pOD =  pObj ? pObj->GetObjData(rRP.m_nProcessThreadID) : 0;
		
		if( pOD && (pOD->m_nCustomFlags & COB_DISABLE_MOTIONBLUR) )
		{
			rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NEAREST];
		}

		const uint32 objFlags = rRP.m_ObjFlags;
		if (objFlags & FOB_NEAREST)
			rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NEAREST];
		if (SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID]==1 && CV_r_usesoftparticles)
		{
			if ((objFlags & FOB_SOFT_PARTICLE) || (rRP.m_PersFlags2 & RBPF2_HALFRES_PARTICLES))
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SOFT_PARTICLE];
		}
		//if (CV_r_useparticles_halfres_debug && (rTI.m_PersFlags2 & RBPF2_HALFRES_PARTICLES))
		//	rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
		if (!(objFlags & FOB_REQUIRES_RESOLVE))
		{
#if defined(DIRECT3D10) && !defined(PS3)
			if ((objFlags & FOB_MOTION_BLUR_PARTICLE) && CV_r_MotionBlur)
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_MOTION_BLUR];
#endif
			// TODO: use special flag for particle in shadow
			if ((objFlags & FOB_INSHADOW) && rRP.m_pShader && rRP.m_pShader->GetShaderType() == eST_Particle || (ef->m_Flags2 & EF2_ALPHABLENDSHADOWS))
				rd->FX_SetupShadowsForTransp();
			if ((objFlags & FOB_GLOBAL_ILLUMINATION) && LPVManager.IsGIRenderable())
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_GLOBAL_ILLUMINATION];
			if (rRP.m_pCurObject->m_RState & OS_DIFFUSE_CUBEMAP)
				rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DIFFUSE_CUBEMAP];
		}
    if (rRP.m_PersFlags2 & RBPF2_OCEANPARTICLES)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_OCEAN_PARTICLE];

		if (rRP.m_pCurObject->m_RState & OS_ANIM_BLEND)
			rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_ANIM_BLEND];

    // Only enable for resources not using zpass
    if (!(rRP.m_pRLD->m_nBatchFlags[rRP.m_nSortGroupID][rRP.m_nPassGroupID] & FB_Z) || (ef->m_Flags & EF_DECAL))
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NOZPASS];                                           

    rRP.m_pCurTechnique = pTech;




    if ((rRP.m_nBatchFilter & (FB_CAUSTICS | FB_MULTILAYERS | FB_LAYER_EFFECT | FB_DEBUG)) && !rRP.m_pReplacementShader)
    {
			if (rRP.m_nBatchFilter & FB_LAYER_EFFECT)
				rd->FX_DrawEffectLayerPasses();

      if (rRP.m_nBatchFilter & FB_MULTILAYERS)
        rd->FX_DrawMultiLayers();

      if (rRP.m_nBatchFilter & FB_CAUSTICS)
        rd->FX_DrawCausticsPasses();

      if (rRP.m_nBatchFilter & FB_DEBUG)
        rd->FX_DrawDebugPasses();
    }
    else
      rd->FX_DrawTechnique(ef, pTech, bGeneral);


		//////////////////////////////////////////////////////////////////////////
    // Depth pass for scattered objects
		// FB_SCATTER should not be processed during z-pass
    if ((rRP.m_nBatchFilter & FB_SCATTER) && !(rRP.m_PersFlags2 & RBPF2_SCATTERPASS))
    {
      pTech = ef->mfGetStartTechnique(rRP.m_nShaderTechnique);
      if (pTech->m_nTechnique[TTYPE_SCATTERPASS] > 0)
      {
				//assert(pTech->m_nTechnique[TTYPE_SCATTERPASS] < (int)ef->m_HWTechniques.Num());
        pTech = ef->m_HWTechniques[pTech->m_nTechnique[TTYPE_SCATTERPASS]];

        rTI.m_PersFlags |= RBPF_ZPASS;
        rd->D3DSetCull(eCULL_Front);
        rRP.m_FlagsPerFlush |= RBSI_LOCKCULL;

        rd->FX_DrawTechnique(ef, pTech, true);
        rTI.m_PersFlags &= ~RBPF_ZPASS;
      }
    }
		//////////////////////////////////////////////////////////////////////////

  }//pTech
  else
  if (ef->m_eSHDType == eSHDT_CustomDraw)
    rd->FX_DrawTechnique(ef, 0, true);

  if (rRP.m_pReplacementShader)
  {
    rd->FX_SetupMultiLayers(false); 
  }

  if (ef->m_Flags & EF_LOCALCONSTANTS)
    rRP.m_PrevLMask = -1;

  PROFILE_SHADER_END

#ifdef DO_RENDERLOG
  sLogFlush("Flush General", ef, pTech);
#endif
}

void CD3D9Renderer::FX_FlushShader_ShadowGen()
{
  CD3D9Renderer *const __restrict rd = gcpRendD3D;
  SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;
  if (!rRP.m_pRE && !rRP.m_RendNumVerts)
    return;

  CShader *ef = rRP.m_pShader;
  if (!ef)
    return;

  //leave out for ps3 since it costs too much
#ifndef PS3
  if (!rRP.m_sExcludeShader.empty())
  {
    char nm[1024];
    strcpy(nm, ef->GetName());
    strlwr(nm);
    if (strstr(rRP.m_sExcludeShader.c_str(), nm))
      return;
  }
#endif

  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];
  assert(rTI.m_PersFlags & RBPF_SHADOWGEN);
  assert(!(rTI.m_PersFlags & RBPF_MAKESPRITE));

  //leave out for ps3 since it costs too much
#ifdef DO_RENDERLOG
  if (rd->m_LogFile)
  {
    if (CV_r_log == 3)
      rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n\n.. Start %s flush: '%s' ..\n", "ShadowGen", ef->GetName());
    if (CV_r_log >= 3)
      rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n");
  }
#endif

  SPipeStat& rPS = rRP.m_PS[rRP.m_nProcessThreadID];
#ifndef _RELEASE
  sBatchStats(rRP);
#endif
  CRenderObject *pObj = rRP.m_pCurObject;

  PROFILE_SHADER_START

#if defined(HW_INSTANCING_ENABLED)
  sDetectInstancing(ef, pObj);
#endif

  // Techniques draw cycle...
  SShaderTechnique *__restrict pTech = ef->mfGetStartTechnique(rRP.m_nShaderTechnique);
  assert(pTech);
  if (!pTech || pTech->m_nTechnique[TTYPE_SHADOWGEN] < 0)
    return;

  if (rd->m_RP.m_pRE)
    rd->m_RP.m_pRE = rd->m_RP.m_RIs[0][0]->pElem;

  rRP.m_pRootTechnique = pTech;

  pTech = ef->m_HWTechniques[pTech->m_nTechnique[TTYPE_SHADOWGEN]];






	const SRenderPipeline::ShadowInfo & shadowInfo = rd->m_RP.m_ShadowInfo;

  if (ef->m_eSHDType == eSHDT_Terrain)
  {
    if (rRP.m_PersFlags2 & RBPF2_VSM)
    {
      rd->D3DSetCull(eCULL_None); 
      rd->m_RP.m_FlagsPerFlush |= RBSI_LOCKCULL;
    }
    else
			if (shadowInfo.m_pCurShadowFrustum->m_Flags & DLF_DIRECTIONAL)
    {
      rd->D3DSetCull(eCULL_None); 
      rd->m_RP.m_FlagsPerFlush |= RBSI_LOCKCULL;
    }
    else 
    {

      //Flipped matrix for point light sources
      //front faces culling by default for terrain
      rd->D3DSetCull(eCULL_Back); 
      rd->m_RP.m_FlagsPerFlush |= RBSI_LOCKCULL;
      //reset slope bias here as well
    }
  }



  // RSMs
	if (shadowInfo.m_pCurShadowFrustum->m_Flags & DLF_REFLECTIVE_SHADOWMAP)
  {
    rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_SAMPLE4 ];
    rd->D3DSetCull(eCULL_Back); 
    rd->m_RP.m_FlagsPerFlush |= RBSI_LOCKCULL;

		const int objFlags = rRP.m_ObjFlags;
		if(objFlags & FOB_DECAL_TEXGEN_2D)
			rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DECAL_TEXGEN_2D];
  }
	else
		if (rRP.m_PersFlags2 & (RBPF2_VSM | RBPF2_DRAWTOCUBE | RBPF2_DISABLECOLORWRITES))
  {
		if (rRP.m_PersFlags2 & RBPF2_DISABLECOLORWRITES)
      rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_HW_PCF_COMPARE ];
    if (rRP.m_PersFlags2 & RBPF2_VSM)
      rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_VARIANCE_SM];
    if (rRP.m_PersFlags2 & RBPF2_DRAWTOCUBE)
      rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_CUBEMAP0];
  }
#ifdef TESSELLATION_RENDERER
  if ((pObj->m_ObjFlags & FOB_NEAREST) || !(pObj->m_ObjFlags & FOB_ALLOW_TESSELLATION))
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
#endif

  //per-object bias for Shadow Generation
  rd->m_cEF.m_TempVecs[1][0] = 0.0f;
  if(!(rRP.m_PersFlags2 & RBPF2_VSM))
  {
    if (rd->m_RP.m_pShaderResources)
    {
      if (rd->m_RP.m_pShaderResources->m_ResFlags & MTL_FLAG_2SIDED)
      {
        //handle terrain self-shadowing and two-sided geom
        rd->m_cEF.m_TempVecs[1][0] = rTI.m_vFrustumInfo.w;
      }

    }
    //don't make per-object bias for global VSM
    //if (rRP.m_pShader->m_eSHDType == eSHDT_Terrain /*&& m_RP.m_vFrustumInfo.x > 100.0f*/) //check for sun && terrain shadows
    //{
    //  rd->m_cEF.m_TempVecs[1][0] = -(rRP.m_vFrustumInfo.w);
    //}
  }

  if (!rd->FX_SetResourcesState())
    return;





  //rd->EF_ApplyQuality();

	const bool bRSMs = shadowInfo.m_pCurShadowFrustum && shadowInfo.m_pCurShadowFrustum->bReflectiveShadowMap;

  if ((rRP.m_ObjFlags & FOB_BENDED) && !bRSMs)
    rRP.m_FlagsShader_MDV |= MDV_BENDING;
  rRP.m_FlagsShader_RT |= rRP.m_pCurObject->m_nRTMask;
  if (rRP.m_RIs[0].Num()<=1 && !(rRP.m_ObjFlags & FOB_TRANS_MASK))
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_OBJ_IDENTITY];
    
    
	// check if MTL_LAYER_BIT_CLOAK_DISSOLVE and some bits in MTL_LAYER_BLEND_CLOAK are set.
	if ((rRP.m_pCurObject->m_nMaterialLayers & MTL_LAYER_BLEND_CLOAK) && (rRP.m_pCurObject->m_nMaterialLayers & MTL_LAYER_BIT_CLOAK_DISSOLVE))
	{
		if ((rRP.m_pCurObject->m_nMaterialLayers & MTL_LAYER_BLEND_CLOAK) == MTL_LAYER_BLEND_CLOAK) //fully blended, dont render
			return;
		rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DISSOLVE];
	}


	if (rRP.m_ObjFlags & FOB_DISSOLVE)
	{
		rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DISSOLVE];
	}

  rRP.m_pCurTechnique = pTech;
	rd->FX_DrawTechnique(ef, pTech, true);

  if (ef->m_Flags & EF_LOCALCONSTANTS)
    rRP.m_PrevLMask = -1;

  PROFILE_SHADER_END

#ifdef DO_RENDERLOG
  sLogFlush("Flush ShadowGen", ef, pTech);
#endif
}

void CD3D9Renderer::FX_FlushShader_ZPass()
{
  CD3D9Renderer *const __restrict rd = gcpRendD3D;
  SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;
  if (!rRP.m_pRE && !rRP.m_RendNumVerts)
    return;

  CShader *ef = rRP.m_pShader;
  if (!ef)
    return;





  //leave out for ps3 since it costs too much
#if !defined(PS3) && !defined(XENON)
  if (!rRP.m_sExcludeShader.empty())  
  {
    char nm[1024];
    strcpy(nm, ef->GetName());
    strlwr(nm);
    if (strstr(rRP.m_sExcludeShader.c_str(), nm))
      return;
  }
#endif

  SThreadInfo& RESTRICT_REFERENCE rTI = rRP.m_TI[rRP.m_nProcessThreadID];
  assert(!(rTI.m_PersFlags & RBPF_SHADOWGEN));
  assert(rRP.m_nBatchFilter & (FB_Z));
  assert(!(rTI.m_PersFlags & RBPF_MAKESPRITE));

#ifdef DO_RENDERLOG
  if (rd->m_LogFile)
  {
    if (CV_r_log == 3)
      rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n\n.. Start %s flush: '%s' ..\n", "ZPass", ef->GetName());
    else
    if (CV_r_log >= 3)
      rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n");
  }
#endif

  if (rd->m_RP.m_pRE)
    rd->m_RP.m_pRE = rd->m_RP.m_RIs[0][0]->pElem;

#ifndef _RELEASE
  sBatchStats(rRP);
#endif
  PROFILE_SHADER_START

#if defined(HW_INSTANCING_ENABLED)
  sDetectInstancing(ef, rRP.m_pCurObject);
#endif

  // Techniques draw cycle...
  SShaderTechnique *__restrict pTech = ef->mfGetStartTechnique(rRP.m_nShaderTechnique);
  if (!pTech || pTech->m_nTechnique[TTYPE_Z] < 0)
    return;

  rRP.m_pRootTechnique = pTech;

  // Skip z-pass if appropriate technique does not exist
  assert(pTech->m_nTechnique[TTYPE_Z] < (int)ef->m_HWTechniques.Num());
  pTech = ef->m_HWTechniques[pTech->m_nTechnique[TTYPE_Z]];

  if (!rd->FX_SetResourcesState())
    return;





  rRP.m_FlagsShader_RT |= rRP.m_pCurObject->m_nRTMask;
  if (rRP.m_ObjFlags & FOB_BENDED)
    rRP.m_FlagsShader_MDV |= MDV_BENDING;

//////////////////////////////////////////////////////////////////////////

  assert(!(rTI.m_PersFlags & RBPF_SHADOWGEN));
  if (!(rRP.m_pCurObject->m_ObjFlags & FOB_NO_STATIC_DECALS)) //|| (ef->m_Flags2 & EF2_DEFERBACKLIGHTING)
  {
    rRP.m_CurStencilRefAndMask = BIT_STENCIL_STATIC;
    //commit stencil state
    rd->FX_SetStencilState(
      STENC_FUNC(FSS_STENCFUNC_ALWAYS) |
      STENCOP_FAIL(FSS_STENCOP_KEEP) |
      STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
      STENCOP_PASS(FSS_STENCOP_REPLACE),
      BIT_STENCIL_STATIC, 0xFF, 0xFF
      );
    rRP.m_ForceStateOr |=	GS_STENCIL;
    //rRP.m_FlagsPerFlush |= RBSI_ENABLESTENCIL;
  }

  if (rRP.m_RIs[0].Num()<=1 && !(rRP.m_ObjFlags & FOB_TRANS_MASK))
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_OBJ_IDENTITY];
 
#ifdef TESSELLATION_RENDERER
  if ((rRP.m_pCurObject->m_ObjFlags & FOB_NEAREST) || !(rRP.m_pCurObject->m_ObjFlags & FOB_ALLOW_TESSELLATION))
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_NO_TESSELLATION];
#endif

	// Set VisArea Stencil Ref
	if (CRenderer::CV_r_DeferredShadingStencilPrepass)
	{
		if (rRP.m_nPassGroupID != EFSLIST_TERRAINLAYER && rRP.m_nPassGroupID != EFSLIST_DECAL)
		{
			rRP.m_ForceStateOr |=	GS_STENCIL;
			const int32 stencilState = STENC_FUNC(FSS_STENCFUNC_ALWAYS) | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_PASS(FSS_STENCOP_REPLACE);
			rd->FX_SetStencilState(stencilState, rd->m_RP.m_RIs[0][0]->nStencRef, 0xFF, 0xFF);
		}
		else
			rRP.m_ForceStateOr &=	~GS_STENCIL;
	}

  rRP.m_pCurTechnique = pTech;
  rd->FX_DrawTechnique(ef, pTech, true);

  rRP.m_ForceStateOr &=	~GS_STENCIL;
  //reset stencil AND mask always
  rRP.m_CurStencilRefAndMask = 0;

  PROFILE_SHADER_END

#ifdef DO_RENDERLOG
  sLogFlush("Flush ZPass", ef, pTech);
#endif
}

void CD3D9Renderer::FX_FlushShader_ShadowPass()
{
  CD3D9Renderer *const __restrict rd = gcpRendD3D;
  SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;
  if (!rRP.m_pRE && !rRP.m_RendNumVerts)
    return;

  CShader *pShader = rRP.m_pShader;

  if (!pShader || !pShader->m_HWTechniques.Num())
    return;
  //  if (rd->m_RP.m_nPassGroupID == EFSLIST_TRANSP_ID)
  {
    if (!rd->FX_SetResourcesState())
      return;
  }
  SShaderTechnique *pTech = pShader->mfGetStartTechnique(rd->m_RP.m_nShaderTechnique);
  if (!pTech || pTech->m_nTechnique[TTYPE_SHADOWPASS] < 0)
    return;

  rRP.m_pRootTechnique = pTech;
  assert(pTech->m_nTechnique[TTYPE_SHADOWPASS] < (int)pShader->m_HWTechniques.Num());
  pTech = pShader->m_HWTechniques[pTech->m_nTechnique[TTYPE_SHADOWPASS]];
  SShaderTechnique *pBaseTech = pTech;



  if (rRP.m_ObjFlags & FOB_SELECTED)
    FX_SelectTechnique(pShader, pTech);

  rd->FX_ApplyShadowQuality();

  if (rRP.m_PersFlags2 & (RBPF2_VSM | RBPF2_DRAWTOCUBE | RBPF2_DISABLECOLORWRITES))
  {
    if (rRP.m_PersFlags2 & RBPF2_DISABLECOLORWRITES)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_HW_PCF_COMPARE ];
    if (rRP.m_PersFlags2 & RBPF2_VSM)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_VARIANCE_SM];
    if (rRP.m_PersFlags2 & RBPF2_DRAWTOCUBE)
      rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_CUBEMAP0];
  }

  rRP.m_FlagsShader_RT |= rRP.m_pCurObject->m_nRTMask;
  if (!(rRP.m_TI[rRP.m_nProcessThreadID].m_PersFlags & RBPF_MAKESPRITE) && (rRP.m_ObjFlags & FOB_BENDED))
    rRP.m_FlagsShader_MDV |= MDV_BENDING;
  if (pShader->m_eShaderType == eST_Particle)
    rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_PARTICLE_SHADOW];

  if (rRP.m_pShaderResources)
  {
    if (rRP.m_pShaderResources->m_ResFlags & MTL_FLAG_2SIDED)
    {
      rd->D3DSetCull(eCULL_None);
      rRP.m_FlagsPerFlush |= RBSI_LOCKCULL;      
    }
    else
    if (rRP.m_pShader->m_eCull != -1)
    {
      rd->D3DSetCull(rRP.m_pShader->m_eCull);
      rRP.m_FlagsPerFlush |= RBSI_LOCKCULL;
    }
  }

#ifndef _RELEASE
  sBatchStats(rRP);
#endif

#if defined(HW_INSTANCING_ENABLED)
  sDetectInstancing(pShader, rRP.m_pCurObject);
#endif

  PROFILE_SHADER_START

#ifdef DO_RENDERLOG
  if (rd->m_LogFile && CV_r_log >= 3)
    rd->Logv(SRendItem::m_RecurseLevel[rRP.m_nProcessThreadID], "\n");
#endif

  rd->FX_DrawShadowPasses(pShader, pTech, rRP.m_nCurLightChan);

  PROFILE_SHADER_END
#ifdef DO_RENDERLOG
  sLogFlush("Flush ShadowPass", pShader, pTech);
#endif
}


//===================================================================================================

int sLimitSizeByScreenRes(uint32 size)
{
  CD3D9Renderer *r = gcpRendD3D;
#if defined (DIRECT3D9)
  while(true)
  {
    if (size > (uint32) r->m_pd3dpp->BackBufferWidth || size > (uint32) r->m_pd3dpp->BackBufferHeight)
      size >>= 1;
    else
      break;
  }
#endif
  return size;
}

static int sTexLimitRes(uint32 nSrcsize, uint32 nDstSize)
{
  while(true)
  {
    if (nSrcsize > nDstSize)
      nSrcsize >>= 1;
    else
      break;
  }
  return nSrcsize;
}

static Matrix34 sMatrixLookAt( const Vec3 &dir,const Vec3 &up,float rollAngle=0 )
{
  Matrix34 M;
  // LookAt transform.
  Vec3 xAxis,yAxis,zAxis;
  Vec3 upVector = up;

  yAxis = -dir.GetNormalized();

  //if (zAxis.x == 0.0 && zAxis.z == 0) up.Set( -zAxis.y,0,0 ); else up.Set( 0,1.0f,0 );

  xAxis = upVector.Cross(yAxis).GetNormalized();
  zAxis = xAxis.Cross(yAxis).GetNormalized();

  // OpenGL kind of matrix.
  M(0,0) = xAxis.x;
  M(0,1) = yAxis.x;
  M(0,2) = zAxis.x;
  M(0,3) = 0;

  M(1,0) = xAxis.y;
  M(1,1) = yAxis.y;
  M(1,2) = zAxis.y;
  M(1,3) = 0;

  M(2,0) = xAxis.z;
  M(2,1) = yAxis.z;
  M(2,2) = zAxis.z;
  M(2,3) = 0;

  if (rollAngle != 0)
  {
    Matrix34 RollMtx;
    RollMtx.SetIdentity();

    float cossin[2];
 //   cry_sincosf(rollAngle, cossin);
		sincos_tpl(rollAngle, &cossin[1],&cossin[0]);

    RollMtx(0,0) = cossin[0]; RollMtx(0,2) = -cossin[1];
    RollMtx(2,0) = cossin[1]; RollMtx(2,2) = cossin[0];

    // Matrix multiply.
    M = RollMtx * M;
  }

  return M;
}

// this is bad: we should re-factor post process stuff to be more general/shareable
static void DrawFullScreenQuad(int nTexWidth, int nTexHeight)
{    
  static SVF_P3F_C4B_T2F pScreenQuad[] =
  {
    { Vec3(0, 0, 0), {{0}}, Vec2(0, 0) },   
    { Vec3(0, 1, 0), {{0}}, Vec2(0, 1) },    
    { Vec3(1, 0, 0), {{0}}, Vec2(1, 0) },   
    { Vec3(1, 1, 0), {{0}}, Vec2(1, 1) },   
  };

  // No offsets required in d3d10
  float fOffsetU = 0.0f;
  float fOffsetV = 0.0f;

#if defined (DIRECT3D9)

  fOffsetU = 0.5f/(float)nTexWidth;
  fOffsetV = 0.5f/(float)nTexHeight;  

#endif

  pScreenQuad[0].xyz = Vec3(-fOffsetU, -fOffsetV, 0);
  pScreenQuad[1].xyz = Vec3(-fOffsetU, 1-fOffsetV, 0);
  pScreenQuad[2].xyz = Vec3(1-fOffsetU, -fOffsetV, 0);
  pScreenQuad[3].xyz = Vec3(1-fOffsetU, 1-fOffsetV, 0);

  CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F);
  gRenDev->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip);
}


void TexBlurAnisotropicVertical(CTexture *pTex, int nAmount, float fScale, float fDistribution, bool bAlphaOnly)
{
  if(!pTex)
  {
    return;
  }
  
  SDynTexture *tpBlurTemp = new SDynTexture(pTex->GetWidth(), pTex->GetHeight(), pTex->GetDstFormat(), eTT_2D,  FT_STATE_CLAMP, "TempBlurAnisoVertRT");
  tpBlurTemp->Update( pTex->GetWidth(), pTex->GetHeight() );

  if( !tpBlurTemp->m_pTexture)
  {
    SAFE_DELETE(tpBlurTemp);
    return;
  }
  
  gcpRendD3D->Set2DMode(true, 1, 1);     


  PROFILE_SHADER_START

    // Get current viewport
    int iTempX, iTempY, iWidth, iHeight;
  gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
  gcpRendD3D->RT_SetViewport(0, 0, pTex->GetWidth(), pTex->GetHeight());        

  Vec4 vWhite( 1.0f, 1.0f, 1.0f, 1.0f );

  static CCryNameTSCRC pTechName("AnisotropicVertical");
  CShader *m_pCurrShader = CShaderMan::m_shPostEffects;

  uint32 nPasses;
  m_pCurrShader->FXSetTechnique(pTechName);
  m_pCurrShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
  m_pCurrShader->FXBeginPass(0);

  gRenDev->FX_SetState(GS_NODEPTHTEST);   

  // setup texture offsets, for texture sampling
  float s1 = 1.0f/(float) pTex->GetWidth();     
  float t1 = 1.0f/(float) pTex->GetHeight();    

  Vec4 pWeightsPS;
  pWeightsPS.x = 0.25f * t1;
  pWeightsPS.y = 0.5f * t1;
  pWeightsPS.z = 0.75f * t1;
  pWeightsPS.w = 1.0f * t1;

  
  pWeightsPS *= -fScale;


  STexState sTexState = STexState(FILTER_LINEAR, true);
  static CCryNameR pParam0Name("blurParams0");

  //SetTexture(pTex, 0, FILTER_LINEAR); 
  
  for(int p(1); p<= nAmount; ++p)   
  {
    //Horizontal

    CShaderMan::m_shPostEffects->FXSetVSFloat(pParam0Name, &pWeightsPS, 1);  
    gcpRendD3D->FX_PushRenderTarget(0, tpBlurTemp->m_pTexture, NULL);
    gcpRendD3D->RT_SetViewport(0, 0, pTex->GetWidth(), pTex->GetHeight());        

    pTex->Apply(0, CTexture::GetTexState(sTexState)); 
    DrawFullScreenQuad(pTex->GetWidth(), pTex->GetHeight());

    gcpRendD3D->FX_PopRenderTarget(0);

    //Vertical

    pWeightsPS *= 2.0f;

    gcpRendD3D->FX_PushRenderTarget(0, pTex, NULL);
    gcpRendD3D->RT_SetViewport(0, 0, pTex->GetWidth(), pTex->GetHeight());         

    CShaderMan::m_shPostEffects->FXSetVSFloat(pParam0Name, &pWeightsPS, 1);  
    tpBlurTemp->m_pTexture->Apply(0, CTexture::GetTexState(sTexState)); 
    DrawFullScreenQuad(pTex->GetWidth(), pTex->GetHeight());      

    gcpRendD3D->FX_PopRenderTarget(0);
  }             

  m_pCurrShader->FXEndPass();
  m_pCurrShader->FXEnd(); 

  // Restore previous viewport
  gcpRendD3D->RT_SetViewport(iTempX, iTempY, iWidth, iHeight);

  //release dyntexture
  SAFE_DELETE(tpBlurTemp);

  gcpRendD3D->FX_Flush();
  PROFILE_SHADER_END      

  gcpRendD3D->Set2DMode(false, 1, 1);     
}


bool CD3D9Renderer::FX_DrawToRenderTarget(CShader *pShader, SRenderShaderResources* pRes, CRenderObject *pObj, SShaderTechnique *pTech, SHRenderTarget *pRT, int nPreprType, CRendElementBase *pRE)
{
   if (!pRT)   
    return false;
   
   int nThreadList = m_pRT->GetThreadList();

   uint32 nPrFlags = pRT->m_nFlags;
   if (nPrFlags & FRT_RENDTYPE_CURSCENE)
     return false;

  if (!pRT->m_pTarget[0] && !pRT->m_pTarget[1])
	{
		if (pRT->m_refSamplerID >=0 && pRT->m_refSamplerID < EFTT_MAX)
		{
			IDynTextureSourceImpl* pDynTexSrc = (IDynTextureSourceImpl*) pRes->m_Textures[pRT->m_refSamplerID]->m_Sampler.m_pDynTexSource;
			assert(pDynTexSrc);
			if (pDynTexSrc)
				return m_pRT->RC_DynTexSourceUpdate(pDynTexSrc, pObj->m_fDistance);
		}
    return false;
	}
  
  CRenderObject *pPrevIgn = m_RP.m_TI[nThreadList].m_pIgnoreObject;
  CTexture *Tex = pRT->m_pTarget[0];
  SEnvTexture *pEnvTex = NULL;
  
  if (nPreprType == SPRID_SCANTEX)
  {
    nPrFlags |= FRT_CAMERA_REFLECTED_PLANE;
    pRT->m_nFlags = nPrFlags;
  }

  if( nPrFlags & FRT_RENDTYPE_CURSCENE )
    return false;
  
  uint32 nWidth = pRT->m_nWidth;
  uint32 nHeight = pRT->m_nHeight;

  if (pRT->m_nIDInPool >= 0)
  {
    assert((int)CTexture::s_CustomRT_2D.Num() > pRT->m_nIDInPool);
    if ((int)CTexture::s_CustomRT_2D.Num() <= pRT->m_nIDInPool)
      return false;
    pEnvTex = &CTexture::s_CustomRT_2D[pRT->m_nIDInPool];

    if (nWidth == -1)
      nWidth = GetWidth();
    if (nHeight == -1)
      nHeight = GetHeight();

		// Very hi specs render reflections at half res - lower specs (and consoles) at quarter res
		float fSizeScale = (CV_r_waterreflections_quality ==5)? 0.5f : 0.25f;
    nWidth = sTexLimitRes(nWidth, uint32(GetWidth() * fSizeScale));
    nHeight = sTexLimitRes(nHeight, uint32(GetHeight() * fSizeScale));    

    ETEX_Format eTF = pRT->m_eTF;
    // $HDR
    if (eTF == eTF_A8R8G8B8 && IsHDRModeEnabled() && m_nHDRType <= 1)
      eTF = eTF_A16B16G16R16F;
    if (pEnvTex && (!pEnvTex->m_pTex || pEnvTex->m_pTex->GetFormat() != eTF))
    {
      char name[128];
      sprintf(name, "$RT_2D_%d", m_TexGenID++);
      int flags = FT_NOMIPS | FT_STATE_CLAMP | FT_DONT_STREAM | FT_DONT_RESIZE;
      pEnvTex->m_pTex = new SDynTexture(nWidth, nHeight, eTF, eTT_2D, flags, name);
    }
    assert(nWidth > 0 && nWidth <= m_d3dsdBackBuffer.Width);
    assert(nHeight > 0 && nHeight <= m_d3dsdBackBuffer.Height);
    Tex = pEnvTex->m_pTex->m_pTexture;
  }
  else
  if (Tex)
  {
    if (Tex->GetCustomID() == TO_RT_2D)
    {
      bool bReflect = false;
      if (nPrFlags & (FRT_CAMERA_REFLECTED_PLANE | FRT_CAMERA_REFLECTED_WATERPLANE))
        bReflect = true;
      Matrix33 orientation = Matrix33(GetCamera().GetMatrix());
      Ang3 Angs = CCamera::CreateAnglesYPR(orientation);
      Vec3 Pos = GetCamera().GetPosition();
      bool bNeedUpdate = false;
			pEnvTex = CTexture::FindSuitableEnvTex(Pos, Angs, false, -1, false, pShader, pRes, pObj, bReflect, pRE, &bNeedUpdate);

      if (!bNeedUpdate)
      {
        if (!pEnvTex)
          return false;
        if (pEnvTex->m_pTex && pEnvTex->m_pTex->m_pTexture)
          return true;
      }
      m_RP.m_TI[nThreadList].m_pIgnoreObject = pObj;
      switch (CRenderer::CV_r_envtexresolution)
      {
      case 0:
        nWidth = 64;
        break;
      case 1:
        nWidth = 128;
        break;
      case 2:
      default:
        nWidth = 256;
        break;
      case 3:
        nWidth = 512;
        break;
      }
      nWidth = sLimitSizeByScreenRes(nWidth);
      nHeight = nWidth;
      if (!pEnvTex->m_pTex->m_pTexture)
      {
        pEnvTex->m_pTex->Update(nWidth, nHeight);
      }
      Tex = pEnvTex->m_pTex->m_pTexture;
    }
    else
    if (Tex->GetCustomID() == TO_RT_CM)
    {
      Vec3 vPos = pObj->GetTranslation();
      float fDistToCam = (vPos-m_RP.m_TI[nThreadList].m_cam.GetPosition()).len();
      CRenderObject *pPrevIgnore = m_RP.m_TI[nThreadList].m_pIgnoreObject;
      m_RP.m_TI[nThreadList].m_pIgnoreObject = pObj;
      pEnvTex = CTexture::FindSuitableEnvCMap(vPos, false, ~0, fDistToCam);
      m_RP.m_TI[nThreadList].m_pIgnoreObject = pPrevIgnore;

      if (pEnvTex && pEnvTex->m_pTex->m_pTexture)
        return true;
      return false;
    }
  }
  if (m_pRT->IsRenderThread() && Tex && Tex->IsLocked())
    return true;

  bool bMGPUAllowNextUpdate = (!(gRenDev->RT_GetCurrGpuID())) && (CRenderer::CV_r_waterreflections_mgpu );

  // always allow for non-mgpu
  if( gRenDev->m_nGPUs == 1 || !CRenderer::CV_r_waterreflections_mgpu )
    bMGPUAllowNextUpdate = true; 

  ETEX_Format eTF = pRT->m_eTF;
  // $HDR
  if (eTF == eTF_A8R8G8B8 && IsHDRModeEnabled() && m_nHDRType <= 1)
    eTF = eTF_A16B16G16R16F;
  if (pEnvTex && (!pEnvTex->m_pTex || pEnvTex->m_pTex->GetFormat() != eTF))
  {
    SAFE_DELETE(pEnvTex->m_pTex);
    char name[128];
    sprintf(name, "$RT_2D_%d", m_TexGenID++);
    int flags = FT_NOMIPS | FT_STATE_CLAMP | FT_DONT_STREAM | FT_DONT_RESIZE;
    pEnvTex->m_pTex = new SDynTexture(nWidth, nHeight, eTF, eTT_2D, flags, name);
    assert(nWidth > 0 && nWidth <= m_d3dsdBackBuffer.Width);
    assert(nHeight > 0 && nHeight <= m_d3dsdBackBuffer.Height);
    pEnvTex->m_pTex->Update(nWidth, nHeight);
  }

  bool bEnableAnisotropicBlur = true;
  switch (pRT->m_eUpdateType)
  {
  case eRTUpdate_WaterReflect:
    {
      if( !CRenderer::CV_r_waterreflections )
      {
        ColorF c = ColorF(0, 0, 0, 1);
        assert(pEnvTex!=NULL);
        if (pEnvTex && pEnvTex->m_pTex && pEnvTex->m_pTex->m_pTexture)
            pEnvTex->m_pTex->m_pTexture->Fill(c);
        return true;
      }

      if( m_RP.m_nLastWaterFrameID == GetFrameID() )
        // water reflection already created this frame, share it
        return true;

      I3DEngine *eng = (I3DEngine *)gEnv->p3DEngine;
      int nVisibleWaterPixelsCount = eng->GetOceanVisiblePixelsCount() / 2; // bug in occlusion query returns 2x more
      int nPixRatioThreshold = (int)(GetWidth() * GetHeight() * CRenderer::CV_r_waterreflections_min_visible_pixels_update);

      static int nVisWaterPixCountPrev = nVisibleWaterPixelsCount;
      if( CRenderer::CV_r_waterreflections_mgpu )
      {
        nVisWaterPixCountPrev = bMGPUAllowNextUpdate ? nVisibleWaterPixelsCount : nVisWaterPixCountPrev;
      }
      else
        nVisWaterPixCountPrev = nVisibleWaterPixelsCount;

      float fUpdateFactorMul = 1.0f;
      float fUpdateDistanceMul = 1.0f;
      if( nVisWaterPixCountPrev < nPixRatioThreshold /4) 
      {
        bEnableAnisotropicBlur = false;
        fUpdateFactorMul = CV_r_waterreflections_minvis_updatefactormul * 10.0f;
        fUpdateDistanceMul = CV_r_waterreflections_minvis_updatedistancemul * 5.0f;
      }
      else
      if( nVisWaterPixCountPrev < nPixRatioThreshold) 
      {
        fUpdateFactorMul = CV_r_waterreflections_minvis_updatefactormul;
        fUpdateDistanceMul = CV_r_waterreflections_minvis_updatedistancemul;
      }

      float fMGPUScale = CRenderer::CV_r_waterreflections_mgpu? (1.0f / (float) gRenDev->m_nGPUs) : 1.0f;
      float fWaterUpdateFactor = CV_r_waterupdateFactor * fUpdateFactorMul * fMGPUScale;
      float fWaterUpdateDistance = CV_r_waterupdateDistance * fUpdateDistanceMul * fMGPUScale;

      float fTimeUpd = min(0.3f, eng->GetDistanceToSectorWithWater());
      fTimeUpd *= fWaterUpdateFactor;
      //if (fTimeUpd > 1.0f)
      //fTimeUpd = 1.0f; 
      Vec3 camView = m_RP.m_TI[nThreadList].m_rcam.ViewDir();
      Vec3 camUp = m_RP.m_TI[nThreadList].m_rcam.Y;

      m_RP.m_nLastWaterFrameID = GetFrameID();

      Vec3 camPos = GetCamera().GetPosition();
      float fDistCam = (camPos - m_RP.m_LastWaterPosUpdate).GetLength();
      float fDotView = camView * m_RP.m_LastWaterViewdirUpdate;
      float fDotUp = camUp * m_RP.m_LastWaterUpdirUpdate;
      float fFOV = GetCamera().GetFov();
      if (m_RP.m_fLastWaterUpdate-1.0f > m_RP.m_TI[nThreadList].m_RealTime)
        m_RP.m_fLastWaterUpdate = m_RP.m_TI[nThreadList].m_RealTime;

      const float fMaxFovDiff = 0.1f;		// no exact test to prevent slowly changing fov causing per frame water reflection updates

      static bool bUpdateReflection = true;
      if( bMGPUAllowNextUpdate )
      {
        bUpdateReflection = m_RP.m_TI[nThreadList].m_RealTime-m_RP.m_fLastWaterUpdate >= fTimeUpd || fDistCam > fWaterUpdateDistance;
        bUpdateReflection = bUpdateReflection || fDotView<0.9f || fabs(fFOV-m_RP.m_fLastWaterFOVUpdate)>fMaxFovDiff;
      }
      
      if ( bUpdateReflection && bMGPUAllowNextUpdate)
      {
        m_RP.m_fLastWaterUpdate = m_RP.m_TI[nThreadList].m_RealTime;
        m_RP.m_LastWaterViewdirUpdate = camView;
        m_RP.m_LastWaterUpdirUpdate = camUp;
        m_RP.m_fLastWaterFOVUpdate = fFOV;
        m_RP.m_LastWaterPosUpdate = camPos;
        assert(pEnvTex!=NULL);
        pEnvTex->m_pTex->ResetUpdateMask();
      }
      else
      if ( !bUpdateReflection )
      {
        assert(pEnvTex!=NULL);
        if ( pEnvTex->m_pTex->IsValid() )
          return true;
      }

      pEnvTex->m_pTex->SetUpdateMask();
    }
    break;
  }

  // Just copy current BB to the render target and exit
  if (nPrFlags & FRT_RENDTYPE_COPYSCENE)
  {
    // Get current render target from the RT stack
    if( !CRenderer::CV_r_debugrefraction )
      FX_ScreenStretchRect( Tex ); // should encode hdr format
    else
    {
      assert(Tex!=NULL);
      ColorF c = ColorF(1, 0, 0, 1);
      Tex->Fill(c);
    }

    return true;
  }

  I3DEngine *eng = (I3DEngine *)gEnv->p3DEngine;
  Matrix44A matProj, matView;
 
  float plane[4];
  bool bUseClipPlane = false;
  bool bChangedCamera = false;

  int nPersFlags = m_RP.m_TI[nThreadList].m_PersFlags;
  //int nPersFlags2 = m_RP.m_TI[nThreadList].m_PersFlags2;
  
  static CCamera tmp_cam_mgpu = GetCamera();
  CCamera tmp_cam = GetCamera();
  CCamera prevCamera = tmp_cam;
  bool bMirror = false;
  bool bOceanRefl = false;

  // Set the camera
  if (nPrFlags & FRT_CAMERA_REFLECTED_WATERPLANE)
  {
    bOceanRefl = true;

    m_RP.m_TI[nThreadList].m_pIgnoreObject = pObj;
    float fMinDist = min(SKY_BOX_SIZE*0.5f, eng->GetDistanceToSectorWithWater()); // 16 is half of skybox size
    float fMaxDist = eng->GetMaxViewDistance();

    Vec3 vPrevPos = tmp_cam.GetPosition();
    Vec4 pOceanParams0, pOceanParams1;
    eng->GetOceanAnimationParams(pOceanParams0, pOceanParams1);

    Plane Pl;
    Pl.n = Vec3(0,0,1);
    Pl.d = eng->GetWaterLevel(); // + CRenderer::CV_r_waterreflections_offset;// - pOceanParams1.x;         
    if ((vPrevPos | Pl.n) - Pl.d < 0)
    {
      Pl.d = -Pl.d;
      Pl.n = -Pl.n;
    }

    plane[0] = Pl.n[0];
    plane[1] = Pl.n[1];
    plane[2] = Pl.n[2];
    plane[3] = -Pl.d ;

    Matrix44 camMat;
    GetModelViewMatrix(camMat.GetData());
    Vec3 vPrevDir = Vec3(-camMat(0,2), -camMat(1,2), -camMat(2,2));
    Vec3 vPrevUp = Vec3(camMat(0,1), camMat(1,1), camMat(2,1));
    Vec3 vNewDir = Pl.MirrorVector(vPrevDir);
    Vec3 vNewUp = Pl.MirrorVector(vPrevUp);
    float fDot = vPrevPos.Dot(Pl.n) - Pl.d;
    Vec3 vNewPos = vPrevPos - Pl.n * 2.0f*fDot;
    Matrix34 m = sMatrixLookAt( vNewDir, vNewUp, tmp_cam.GetAngles()[2] );

		// New position + offset along view direction - minimizes projection artefacts
		m.SetTranslation(vNewPos + Vec3(vNewDir.x, vNewDir.y, 0));

    tmp_cam.SetMatrix(m);

    float fDistOffset = fMinDist;
    if( CV_r_waterreflections_use_min_offset )
    {
      fDistOffset = max( fMinDist, 2.0f * gEnv->p3DEngine->GetDistanceToSectorWithWater() );
      if ( fDistOffset  >= fMaxDist ) // engine returning bad value
        fDistOffset = fMinDist; 
    }

		assert(pEnvTex);
    tmp_cam.SetFrustum((int)(pEnvTex->m_pTex->GetWidth()*tmp_cam.GetProjRatio()), pEnvTex->m_pTex->GetHeight(), tmp_cam.GetFov(), fDistOffset, fMaxDist); //tmp_cam.GetFarPlane());

    // Allow camera update
    if( bMGPUAllowNextUpdate ) 
      tmp_cam_mgpu = tmp_cam;

    SetCamera( tmp_cam_mgpu );
    bChangedCamera = true;
    bUseClipPlane = true;
    bMirror = true;
    //m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_MIRRORCULL;
  }
  else
  if (nPrFlags & FRT_CAMERA_REFLECTED_PLANE)
  {
    m_RP.m_TI[nThreadList].m_pIgnoreObject = pObj;
    float fMinDist = 0.25f;
    float fMaxDist = eng->GetMaxViewDistance();

    Vec3 vPrevPos = tmp_cam.GetPosition();

    if (pRes && pRes->m_pCamera)
    {
      tmp_cam = *pRes->m_pCamera; // Portal case
      //tmp_cam.SetPosition(Vec3(310, 150, 30));
      //tmp_cam.SetAngles(Vec3(-90,0,0));
      //tmp_cam.SetFrustum((int)(Tex->GetWidth()*tmp_cam.GetProjRatio()), Tex->GetHeight(), tmp_cam.GetFov(), fMinDist, tmp_cam.GetFarPlane());

      SetCamera(tmp_cam);
      bUseClipPlane = false;
      bMirror = false;
    }
    else
    { // Mirror case
      Plane Pl;
      pRE->mfGetPlane(Pl);
      //Pl.d = -Pl.d;
      if (pObj)
      {
        Matrix44 mat = GetTransposed44(Matrix44(pObj->m_II.m_Matrix));
        Pl = TransformPlane(mat, Pl);
      }
      if ((vPrevPos | Pl.n) - Pl.d < 0)
      {
        Pl.d = -Pl.d;
        Pl.n = -Pl.n;
      }

      plane[0] = Pl.n[0];
      plane[1] = Pl.n[1];
      plane[2] = Pl.n[2];
      plane[3] = -Pl.d;

      //this is the new code to calculate the reflection matrix

      Matrix44A camMat;
      GetModelViewMatrix(camMat.GetData());
      Vec3 vPrevDir = Vec3(-camMat(0,2), -camMat(1,2), -camMat(2,2));
      Vec3 vPrevUp = Vec3(camMat(0,1), camMat(1,1), camMat(2,1));
      Vec3 vNewDir = Pl.MirrorVector(vPrevDir);
      Vec3 vNewUp = Pl.MirrorVector(vPrevUp);
      float fDot = vPrevPos.Dot(Pl.n) - Pl.d;
      Vec3 vNewPos = vPrevPos - Pl.n * 2.0f*fDot;
      Matrix34A m = sMatrixLookAt( vNewDir, vNewUp, tmp_cam.GetAngles()[2] );
      m.SetTranslation(vNewPos);
      tmp_cam.SetMatrix(m);

      //Matrix34 RefMatrix34 = CreateReflectionMat3(Pl);
      //Matrix34 matMir=RefMatrix34*tmp_cam.GetMatrix();
      //tmp_cam.SetMatrix(matMir);
			assert(Tex);
      tmp_cam.SetFrustum((int)(Tex->GetWidth()*tmp_cam.GetProjRatio()), Tex->GetHeight(), tmp_cam.GetFov(), fMinDist, fMaxDist); //tmp_cam.GetFarPlane());
      bMirror = true;
      bUseClipPlane = true;
    }
    SetCamera(tmp_cam);
    bChangedCamera = true;
    //m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_MIRRORCULL;
  }
  else
  if (((nPrFlags & FRT_CAMERA_CURRENT) || (nPrFlags & FRT_RENDTYPE_CURSCENE)) && pRT->m_eOrder == eRO_PreDraw && !(nPrFlags & FRT_RENDTYPE_CUROBJECT))
  {
    // Always restore stuff after explicitly changing...

    // get texture surface
    // Get current render target from the RT stack
    if( !CRenderer::CV_r_debugrefraction )
      FX_ScreenStretchRect( Tex ); // should encode hdr format
    else
    {
      ColorF c = ColorF(1, 0, 0, 1);
      Tex->Fill(c);
    }

    m_RP.m_TI[nThreadList].m_pIgnoreObject = pPrevIgn;    
    return true;
  }
  /*	if (pRT->m_nFlags & FRT_CAMERA_CURRENT)
  {
  //m_RP.m_pIgnoreObject = pObj;

  SetCamera(tmp_cam);
  bChangedCamera = true;
  bUseClipPlane = true;
  }*/

  bool bRes = true;

  m_pRT->RC_PushVP();
  m_pRT->RC_PushFog();
  m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_DRAWTOTEXTURE | RBPF_ENCODE_HDR;

  if (m_LogFile)
    Logv(SRendItem::m_RecurseLevel[nThreadList], "*** Set RT for Water reflections ***\n");

	assert(pEnvTex);
  m_pRT->RC_SetEnvTexRT(pEnvTex, pRT->m_bTempDepth ? pEnvTex->m_pTex->GetWidth() : -1, pRT->m_bTempDepth ? pEnvTex->m_pTex->GetHeight() : -1, true);
  m_pRT->RC_ClearRT(pRT->m_nFlags|FRT_CLEAR_IMMEDIATE, &pRT->m_ClearColor, pRT->m_fClearDepth);

  float fAnisoScale = 1.0f;
  if (pRT->m_nFlags & FRT_RENDTYPE_CUROBJECT)
  {
    CCryNameR& nameTech = pTech->m_NameStr;
    char newTech[128];
    sprintf(newTech, "%s_RT", nameTech.c_str());
    SShaderTechnique *pT = pShader->mfFindTechnique(newTech);
    if (!pT)
      iLog->Log("Error: CD3D9Renderer::FX_DrawToRenderTarget: Couldn't find technique '%s' in shader '%s'\n", newTech, pShader->GetName());
    else
    {
      FX_ObjectChange(pShader, pRes, pObj, pRE);
      FX_Start(pShader, -1, pRes, pRE);
      pRE->mfPrepare(false);
      FX_DrawShader_General(pShader, pT);
    }
  }
  else
  {
    if (bMirror)
    {
      if( bOceanRefl )
        SetCamera(tmp_cam);

			m_pRT->RC_SetEnvTexMatrix(pEnvTex);

      if( bOceanRefl )
        SetCamera(tmp_cam_mgpu);
    }

		m_RP.m_TI[nThreadList].m_PersFlags |= RBPF_OBLIQUE_FRUSTUM_CLIPPING;   
		//m_RP.m_TI[nThreadList].m_PersFlags2 |= RBPF_MIRRORCAMERA;// | RBPF_MIRRORCULL; ??

    Plane p;
    p.n[0] = plane[0];
    p.n[1] = plane[1];
    p.n[2] = plane[2];
    p.d = plane[3]; // +0.25f;    
    fAnisoScale = plane[3];
    fAnisoScale = fabs(fabs(fAnisoScale) - GetCamera().GetPosition().z); 
    m_RP.m_TI[nThreadList].m_bObliqueClipPlane = true;

    // put clipplane in clipspace..
		Matrix44A mView, mProj, mCamProj, mInvCamProj;
		GetModelViewMatrix(&mView(0,0));
		GetProjectionMatrix(&mProj(0,0));  
		mCamProj.Multiply(mView, mProj);
		mInvCamProj.Invert(mCamProj);
    m_RP.m_TI[nThreadList].m_pObliqueClipPlane = TransformPlane2(mInvCamProj, p);

    int RendFlags = (gRenDev->m_RP.m_eQuality)? DLD_TERRAIN : 0;    

    int nReflQuality = ( bOceanRefl )? (int)CV_r_waterreflections_quality : (int)CV_r_reflections_quality; 

    // set reflection quality setting
    switch( nReflQuality )
    {
      case 1: RendFlags |= DLD_ENTITIES;   break;
      case 2: RendFlags |= DLD_DETAIL_TEXTURES | DLD_ENTITIES ;   break;
      case 3: 
        RendFlags |= DLD_STATIC_OBJECTS | DLD_ENTITIES|DLD_DETAIL_TEXTURES;
          break;
      case 4: 
		  case 5: 
        RendFlags |= DLD_STATIC_OBJECTS | DLD_ENTITIES|DLD_DETAIL_TEXTURES|DLD_PARTICLES;
        break;
    }

    int nRFlags = SHDF_ALLOWHDR | SHDF_NO_DRAWNEAR;
 
    // disable caustics if camera above water
    if( p.d < 0)
      nRFlags |= SHDF_NO_DRAWCAUSTICS;

    eng->RenderWorld(nRFlags, bOceanRefl ? &tmp_cam_mgpu : &tmp_cam, 1, __FUNCTION__, RendFlags, pRT->m_nFilterFlags);
    
    m_RP.m_TI[nThreadList].m_bObliqueClipPlane = false;
    m_RP.m_TI[nThreadList].m_PersFlags &= ~RBPF_OBLIQUE_FRUSTUM_CLIPPING;
  }
  m_pRT->RC_PopRT(0);

  // Very Hi specs get anisotropic reflections
  int nReflQuality = ( bOceanRefl )? (int)CV_r_waterreflections_quality : (int)CV_r_reflections_quality; 
  if( nReflQuality >= 4 && bEnableAnisotropicBlur && Tex && Tex->GetDevTexture())
    m_pRT->RC_TexBlurAnisotropicVertical(Tex, fAnisoScale);

  if (m_LogFile)
    Logv(SRendItem::m_RecurseLevel[nThreadList], "*** End RT for Water reflections ***\n");

  // todo: encode hdr format

  m_RP.m_TI[nThreadList].m_PersFlags = nPersFlags;
	//m_RP.m_TI[nThreadList].m_PersFlags2 = nPersFlags2;

  if (bChangedCamera)
    SetCamera(prevCamera);

  m_pRT->RC_PopVP();
  m_pRT->RC_PopFog();

  // increase frame id to support multiple recursive draws
  m_RP.m_TI[nThreadList].m_pIgnoreObject = pPrevIgn;
  m_RP.m_TI[nThreadList].m_nFrameID++;

  return bRes;
}















































































































#if SUPPORT_RENDER_TO_CONTROLLER
#include "D3DPostProcess.h"
void CD3D9Renderer::FX_UpdateControllerBuffers()
{ 
	CD3D9Renderer *const __restrict rd = gcpRendD3D;


	PostProcessUtils().CopyScreenToTexture(CTexture::s_ptexBackBuffer);  // Can copy direct to DRC surface due to a bug API is not supposed to be used for stretching.
	PostProcessUtils().StretchRect(CTexture::s_ptexBackBuffer, CTexture::s_ptexDRC);

	//rd->FX_PushRenderTarget(0, CTexture::s_ptexDRC, NULL);

	// DO DRC SPECIFIC RENDERING .....

	//rd->FX_PopRenderTarget(0);
}
#endif
